FastAPI is not loading static files
Question:
So, I’m swapping my project from node.js to python FastAPI. Everything has been working fine with node, but here it says that my static files are not present, so here’s the code:
from fastapi import FastAPI, Request, WebSocket
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
app = FastAPI()
app.mount("/static", StaticFiles(directory="../static"), name="static")
templates = Jinja2Templates(directory='../templates')
@app.get('/')
async def index_loader(request: Request):
return templates.TemplateResponse('index.html', {"request": request})
The project’s structure looks like this:

Files are clearly where they should be, but when I connect to the website, the following error occurs:
←[32mINFO←[0m: connection closed
←[32mINFO←[0m: 127.0.0.1:54295 - "←[1mGET /img/separator.png HTTP/1.1←[0m" ←[31m404 Not Found←[0m
←[32mINFO←[0m: 127.0.0.1:54296 - "←[1mGET /css/rajdhani.css HTTP/1.1←[0m" ←[31m404 Not Found←[0m
←[32mINFO←[0m: 127.0.0.1:54295 - "←[1mGET /js/pixi.min.js HTTP/1.1←[0m" ←[31m404 Not Found←[0m
←[32mINFO←[0m: 127.0.0.1:54296 - "←[1mGET /js/ease.js HTTP/1.1←[0m" ←[31m404 Not Found←[0m
←[32mINFO←[0m: 127.0.0.1:54298 - "←[1mGET / HTTP/1.1←[0m" ←[32m200 OK←[0m
←[32mINFO←[0m: 127.0.0.1:54298 - "←[1mGET /img/separator.png HTTP/1.1←[0m" ←[31m404 Not Found←[0m
←[32mINFO←[0m: 127.0.0.1:54299 - "←[1mGET /css/rajdhani.css HTTP/1.1←[0m" ←[31m404 Not Found←[0m
←[32mINFO←[0m: 127.0.0.1:54298 - "←[1mGET /js/pixi.min.js HTTP/1.1←[0m" ←[31m404 Not Found←[0m
←[32mINFO←[0m: 127.0.0.1:54299 - "←[1mGET /js/ease.js HTTP/1.1←[0m" ←[31m404 Not Found←[0m
So, basically, any static file that I’m using is missing, and I have no idea what I am doing wrong. How to fix it?
Answers:
Here:
app.mount("/static", StaticFiles(directory="../static"), name="static")
You mount your static directory under /static
path. That means, if you want access static files in your html you need to use static
prefix, e.g. <img src="static/img/separator.png"/>
To mount a StaticFiles
instance to a specific path, you could use the following:
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
To link to static
files from within your Jinja2 (HTML) template, you could use the following, as described in Starlette documentation:
<link href="{{ url_for('static', path='/css/rajdhani.css') }}" rel="stylesheet">
Alternatively, you could directly use the pathname given when you mounted a StaticFiles
instance (in this case, that is, /static
). Any path that starts with /static
will be handled by it. Example below:
<link href="static/css/rajdhani.css'" rel="stylesheet">
folder = os.path.dirname(__file__)
app.mount("/static", StaticFiles(directory=folder+"/../static",html=True), name="static")
works. Somehow using directory="../static"
does not work, the full path is required when pointing outside of your FastAPI project. Then html=True
is also needed for serving html files correctly. See https://www.starlette.io/staticfiles/.
So, I’m swapping my project from node.js to python FastAPI. Everything has been working fine with node, but here it says that my static files are not present, so here’s the code:
from fastapi import FastAPI, Request, WebSocket
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
app = FastAPI()
app.mount("/static", StaticFiles(directory="../static"), name="static")
templates = Jinja2Templates(directory='../templates')
@app.get('/')
async def index_loader(request: Request):
return templates.TemplateResponse('index.html', {"request": request})
The project’s structure looks like this:
Files are clearly where they should be, but when I connect to the website, the following error occurs:
←[32mINFO←[0m: connection closed
←[32mINFO←[0m: 127.0.0.1:54295 - "←[1mGET /img/separator.png HTTP/1.1←[0m" ←[31m404 Not Found←[0m
←[32mINFO←[0m: 127.0.0.1:54296 - "←[1mGET /css/rajdhani.css HTTP/1.1←[0m" ←[31m404 Not Found←[0m
←[32mINFO←[0m: 127.0.0.1:54295 - "←[1mGET /js/pixi.min.js HTTP/1.1←[0m" ←[31m404 Not Found←[0m
←[32mINFO←[0m: 127.0.0.1:54296 - "←[1mGET /js/ease.js HTTP/1.1←[0m" ←[31m404 Not Found←[0m
←[32mINFO←[0m: 127.0.0.1:54298 - "←[1mGET / HTTP/1.1←[0m" ←[32m200 OK←[0m
←[32mINFO←[0m: 127.0.0.1:54298 - "←[1mGET /img/separator.png HTTP/1.1←[0m" ←[31m404 Not Found←[0m
←[32mINFO←[0m: 127.0.0.1:54299 - "←[1mGET /css/rajdhani.css HTTP/1.1←[0m" ←[31m404 Not Found←[0m
←[32mINFO←[0m: 127.0.0.1:54298 - "←[1mGET /js/pixi.min.js HTTP/1.1←[0m" ←[31m404 Not Found←[0m
←[32mINFO←[0m: 127.0.0.1:54299 - "←[1mGET /js/ease.js HTTP/1.1←[0m" ←[31m404 Not Found←[0m
So, basically, any static file that I’m using is missing, and I have no idea what I am doing wrong. How to fix it?
Here:
app.mount("/static", StaticFiles(directory="../static"), name="static")
You mount your static directory under /static
path. That means, if you want access static files in your html you need to use static
prefix, e.g. <img src="static/img/separator.png"/>
To mount a StaticFiles
instance to a specific path, you could use the following:
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
To link to static
files from within your Jinja2 (HTML) template, you could use the following, as described in Starlette documentation:
<link href="{{ url_for('static', path='/css/rajdhani.css') }}" rel="stylesheet">
Alternatively, you could directly use the pathname given when you mounted a StaticFiles
instance (in this case, that is, /static
). Any path that starts with /static
will be handled by it. Example below:
<link href="static/css/rajdhani.css'" rel="stylesheet">
folder = os.path.dirname(__file__)
app.mount("/static", StaticFiles(directory=folder+"/../static",html=True), name="static")
works. Somehow using directory="../static"
does not work, the full path is required when pointing outside of your FastAPI project. Then html=True
is also needed for serving html files correctly. See https://www.starlette.io/staticfiles/.