or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-responses.mdapi-routing.mdbackground-tasks.mdcore-application.mddata-utilities.mddependency-injection.mdexception-handling.mdindex.mdmiddleware.mdrequest-parameters.mdrequest-response.mdsecurity-authentication.mdstatic-templating.mdtesting.mdwebsocket-support.md

static-templating.mddocs/

0

# Static Files and Templating

1

2

FastAPI provides built-in support for serving static files and rendering HTML templates, enabling the creation of full web applications that combine API endpoints with frontend content. This functionality is essential for applications that need to serve HTML pages, CSS, JavaScript, images, and other static assets alongside their API functionality.

3

4

## Capabilities

5

6

### Static Files Serving

7

8

Class for serving static files such as HTML, CSS, JavaScript, images, and other assets from the filesystem.

9

10

```python { .api }

11

class StaticFiles:

12

def __init__(

13

self,

14

*,

15

directory: str = None,

16

packages: List[str] = None,

17

html: bool = False,

18

check_dir: bool = True,

19

follow_symlink: bool = False,

20

) -> None:

21

"""

22

Create static files application for serving static content.

23

24

Parameters:

25

- directory: Directory path containing static files

26

- packages: List of Python packages containing static files

27

- html: Whether to serve HTML files for directory requests

28

- check_dir: Whether to check if directory exists on startup

29

- follow_symlink: Whether to follow symbolic links

30

"""

31

```

32

33

### Jinja2 Template Engine

34

35

Template engine integration for rendering dynamic HTML content with data from your API endpoints.

36

37

```python { .api }

38

class Jinja2Templates:

39

def __init__(self, directory: str) -> None:

40

"""

41

Create Jinja2 templates instance.

42

43

Parameters:

44

- directory: Directory containing template files

45

"""

46

47

def TemplateResponse(

48

self,

49

name: str,

50

context: dict,

51

status_code: int = 200,

52

headers: dict = None,

53

media_type: str = None,

54

background: BackgroundTask = None,

55

) -> TemplateResponse:

56

"""

57

Render template with context data and return as HTTP response.

58

59

Parameters:

60

- name: Template file name

61

- context: Dictionary of template variables

62

- status_code: HTTP status code

63

- headers: Additional HTTP headers

64

- media_type: Response content type

65

- background: Background task to run after response

66

67

Returns:

68

TemplateResponse with rendered HTML content

69

"""

70

71

def get_template(self, name: str) -> Template:

72

"""Get template object by name."""

73

```

74

75

## Usage Examples

76

77

### Serving Static Files

78

79

```python

80

from fastapi import FastAPI

81

from fastapi.staticfiles import StaticFiles

82

83

app = FastAPI()

84

85

# Mount static files directory

86

app.mount("/static", StaticFiles(directory="static"), name="static")

87

88

# Mount static files with HTML serving

89

app.mount("/public", StaticFiles(directory="public", html=True), name="public")

90

91

# Serve from Python package

92

app.mount("/assets", StaticFiles(packages=["mypackage"]), name="assets")

93

```

94

95

With this setup:

96

- Files in `./static/` are accessible at `/static/filename.ext`

97

- Files in `./public/` are accessible at `/public/filename.ext`

98

- Directory requests to `/public/` will serve `index.html` if `html=True`

99

- Package assets are served from installed Python packages

100

101

### HTML Template Rendering

102

103

```python

104

from fastapi import FastAPI, Request

105

from fastapi.templating import Jinja2Templates

106

from fastapi.responses import HTMLResponse

107

108

app = FastAPI()

109

templates = Jinja2Templates(directory="templates")

110

111

@app.get("/", response_class=HTMLResponse)

112

async def home(request: Request):

113

return templates.TemplateResponse(

114

"index.html",

115

{"request": request, "title": "Home Page"}

116

)

117

118

@app.get("/user/{user_id}", response_class=HTMLResponse)

119

async def user_profile(request: Request, user_id: int):

120

# Simulate user data retrieval

121

user_data = {"id": user_id, "name": f"User {user_id}"}

122

return templates.TemplateResponse(

123

"profile.html",

124

{

125

"request": request,

126

"user": user_data,

127

"title": f"Profile - {user_data['name']}"

128

}

129

)

130

```

131

132

Template file `templates/index.html`:

133

134

```html

135

<!DOCTYPE html>

136

<html>

137

<head>

138

<title>{{ title }}</title>

139

<link rel="stylesheet" href="/static/style.css">

140

</head>

141

<body>

142

<h1>Welcome to FastAPI</h1>

143

<p>This is a template-rendered page.</p>

144

<script src="/static/script.js"></script>

145

</body>

146

</html>

147

```

148

149

Template file `templates/profile.html`:

150

151

```html

152

<!DOCTYPE html>

153

<html>

154

<head>

155

<title>{{ title }}</title>

156

</head>

157

<body>

158

<h1>User Profile</h1>

159

<p>ID: {{ user.id }}</p>

160

<p>Name: {{ user.name }}</p>

161

<a href="/">Back to Home</a>

162

</body>

163

</html>

164

```

165

166

### Complete Web Application Example

167

168

```python

169

from fastapi import FastAPI, Request, Form

170

from fastapi.templating import Jinja2Templates

171

from fastapi.staticfiles import StaticFiles

172

from fastapi.responses import HTMLResponse, RedirectResponse

173

from typing import Optional

174

175

app = FastAPI()

176

177

# Mount static files for CSS, JS, images

178

app.mount("/static", StaticFiles(directory="static"), name="static")

179

180

# Setup templates

181

templates = Jinja2Templates(directory="templates")

182

183

# In-memory storage for demo

184

items = []

185

186

@app.get("/", response_class=HTMLResponse)

187

async def home(request: Request):

188

return templates.TemplateResponse(

189

"home.html",

190

{"request": request, "items": items}

191

)

192

193

@app.get("/add", response_class=HTMLResponse)

194

async def add_item_form(request: Request):

195

return templates.TemplateResponse(

196

"add_item.html",

197

{"request": request}

198

)

199

200

@app.post("/add")

201

async def add_item(

202

request: Request,

203

name: str = Form(...),

204

description: str = Form(...)

205

):

206

item = {"id": len(items) + 1, "name": name, "description": description}

207

items.append(item)

208

return RedirectResponse(url="/", status_code=303)

209

210

@app.get("/item/{item_id}", response_class=HTMLResponse)

211

async def item_detail(request: Request, item_id: int):

212

item = next((item for item in items if item["id"] == item_id), None)

213

if not item:

214

return templates.TemplateResponse(

215

"404.html",

216

{"request": request},

217

status_code=404

218

)

219

return templates.TemplateResponse(

220

"item_detail.html",

221

{"request": request, "item": item}

222

)

223

224

# API endpoints for AJAX/SPA integration

225

@app.get("/api/items")

226

async def api_get_items():

227

return {"items": items}

228

229

@app.post("/api/items")

230

async def api_add_item(item: dict):

231

new_item = {"id": len(items) + 1, **item}

232

items.append(new_item)

233

return new_item

234

```

235

236

### Template with Custom Filters

237

238

```python

239

from fastapi import FastAPI, Request

240

from fastapi.templating import Jinja2Templates

241

import datetime

242

243

app = FastAPI()

244

templates = Jinja2Templates(directory="templates")

245

246

# Add custom filter to templates

247

def format_datetime(value):

248

return value.strftime("%Y-%m-%d %H:%M:%S")

249

250

templates.env.filters["datetime"] = format_datetime

251

252

@app.get("/dashboard", response_class=HTMLResponse)

253

async def dashboard(request: Request):

254

return templates.TemplateResponse(

255

"dashboard.html",

256

{

257

"request": request,

258

"current_time": datetime.datetime.now(),

259

"data": {"users": 150, "posts": 1240}

260

}

261

)

262

```

263

264

Template using custom filter:

265

266

```html

267

<!DOCTYPE html>

268

<html>

269

<head>

270

<title>Dashboard</title>

271

</head>

272

<body>

273

<h1>Dashboard</h1>

274

<p>Current time: {{ current_time | datetime }}</p>

275

<p>Users: {{ data.users }}</p>

276

<p>Posts: {{ data.posts }}</p>

277

</body>

278

</html>

279

```

280

281

### Error Page Templates

282

283

```python

284

from fastapi import FastAPI, Request, HTTPException

285

from fastapi.templating import Jinja2Templates

286

from fastapi.responses import HTMLResponse

287

288

app = FastAPI()

289

templates = Jinja2Templates(directory="templates")

290

291

@app.exception_handler(404)

292

async def not_found_handler(request: Request, exc: HTTPException):

293

return templates.TemplateResponse(

294

"404.html",

295

{"request": request},

296

status_code=404

297

)

298

299

@app.exception_handler(500)

300

async def server_error_handler(request: Request, exc: HTTPException):

301

return templates.TemplateResponse(

302

"500.html",

303

{"request": request},

304

status_code=500

305

)

306

```

307

308

## Types

309

310

```python { .api }

311

from typing import Any, Dict, List, Optional

312

from starlette.responses import Response

313

from starlette.background import BackgroundTask

314

from starlette.templating import _TemplateResponse as TemplateResponse

315

from jinja2 import Template, Environment

316

317

# Template response type

318

TemplateResponse = _TemplateResponse

319

320

# Jinja2 environment type

321

Jinja2Environment = Environment

322

323

# Template context type

324

TemplateContext = Dict[str, Any]

325

```