Middleware and Cookies
By Syncfusion®, Inc. · Last updated
What middleware is, src/middleware.ts, defineMiddleware(), next() and changing responses, sequence(), redirects and rewrites in middleware, sharing data with locals, App.Locals, and reading, setting and deleting cookies with their options.
Middleware
- Middleware = code that runs before a page or endpoint, for every request.
- It can read the request, add data for the page, or answer early with a redirect.
- It can also run after the page, to change the response.
- In this lesson, you will write middleware and use cookies, small pieces of data stored in the visitor's browser.
Simple lesson: middleware is a gate every request passes through.
A Real-World Example
- Asha wants every page to know the visitor's preferred language and to log how long each page takes.
- Adding that code to every page would mean copying it many times.
- She writes it once in
src/middleware.ts. Every request runs it.
Press ▶ Run. Visit both pages. The Terminal shows the middleware running before each one.
What happened:
onRequestran first. It putgreetingintocontext.locals.await next()ran the page. The page readAstro.locals.greeting.- After
next(), the middleware ran again and logged the time.
What You Will Learn
In this lesson, you will learn:
- How to create middleware in
src/middleware.ts. - What
next()does, and how to change the response. - How to chain several middleware with
sequence(). - How to redirect or rewrite from middleware.
- How to share data with pages through
locals. - How to read, set and delete cookies.
- Which cookie options keep them safe.
Creating Middleware
src/middleware.ts or src/middleware.js
- [TS] Create
src/middleware.ts. [JS] Createsrc/middleware.js. - Export a function called
onRequest. - It runs for every on-demand request. For static pages, it runs once each, at build time.
defineMiddleware()
defineMiddleware()fromastro:middlewarewraps your function.- It changes nothing at run time. It gives your editor the right types for
contextandnext.
next() and Modifying Responses
next()= "run the rest: other middleware, then the page".- It returns the page's
Response. - After it, you can change the response, such as adding a header:
response.headers.set("X-Powered-By", "Asha"). - If you never call
next(), the page never runs. You must then return your own response.
Animation: a request enters middleware, which calls next(), the page runs, and the response passes back through the middleware before reaching the browser.
Browser
Middleware before: set locals await next() after: add headers
Page
The request goes in through the middleware, and the response comes back out through it.
Chaining with sequence()
sequence(a, b, c)fromastro:middlewareruns several middleware in order.- Each one calls
next()to pass control to the next. - Keep each middleware small, with one job: logging, auth, language and so on.
Order matters in sequence(). Put logging first so it sees every request, and auth before anything that needs to know the user.
Press ▶ Run. Read the order in the Terminal: in through log, then lang, out in reverse.
Simple lesson: onRequest runs around every request. next() runs the page. sequence() chains several.
Redirects, Rewrites and locals
Redirecting and Rewriting from Middleware
return context.redirect("/login")= send the visitor elsewhere. The page does not run.return context.rewrite("/maintenance")= show another page's content at the same address.- Use these for rules that apply to many pages, such as "every
/adminpage needs a login".
context.locals
- locals = an object that lives for one request only.
- Middleware writes to it:
context.locals.user = .... - Pages read it:
Astro.locals.user. Endpoints readcontext.locals.user. - Nothing in
localsreaches the browser unless a page shows it.
[TS] Typing App.Locals
- Describe your locals in
src/env.d.ts, so pages know their types:
declare namespace App {
interface Locals {
lang: "en" | "ta";
user?: { name: string };
}
}
- [JS] You do not need this.
localsis a plain object.
Config redirects (from Routing) are simpler for fixed lists. Middleware redirects are for rules, such as "anything that starts with /old-blog".
Simple lesson: middleware can redirect or rewrite, and passes data to pages through locals.
Cookies
What Cookies Are
- Cookie = a small piece of text the browser stores for one website, and sends back with every request to it.
- Examples: a theme choice, a "seen the banner" flag, a session ID.
- A cookie is per visitor. Each browser has its own.
Reading Cookies
Astro.cookies.get("theme")returns the cookie, orundefined.Astro.cookies.has("theme")returnstrueorfalse.Read its value in the form you need:
.value= the text,.number()= a number,.boolean()=trueorfalse,.json()= an object, if you stored JSON.
Setting Cookies
Astro.cookies.set("theme", "dark", { path: "/" }).- Objects are stored as JSON:
Astro.cookies.set("prefs", { fontSize: 18 }). - Setting a cookie only works in on-demand pages, endpoints, middleware and actions.
Deleting Cookies
Astro.cookies.delete("theme", { path: "/" }).- Use the same
pathas when you set it.
Cookies in Endpoints and Middleware
- In endpoints, actions and middleware, use
context.cookies. It works the same way.
Press ▶ Run. Visit the page a few times. Then reset the counter. The Terminal shows each cookie change.
Cookie Options
path= which addresses get the cookie."/"means the whole site.maxAge= seconds until it expires.expires= an exact date. Without either, it ends when the browser closes.httpOnly= browser JavaScript cannot read it. Use it for anything sensitive.secure= only sent over HTTPS.sameSite= whether other websites' requests carry it:"strict"= never,"lax"= only for normal link clicks (a good default),"none"= always (needssecure).
domain= share it with sub-domains, such asblog.asha.dev.partitioned= keep a third-party cookie separate per site. Rarely needed.
Cookies travel with every request and the visitor can edit them. Never store passwords or trust a cookie's value without checking it. Keep private data on the server, in a session.
Merging and Reading Set-Cookie Headers (Advanced)
cookies.merge(other)joins cookies from anotherAstroCookiesobject.cookies.headers()lists theSet-Cookieheader values Astro will send. Useful in tests and custom middleware.
Press ▶ Run. Pick a theme. It is saved as a JSON cookie, and read back on every page.
Simple lesson: get(), has(), set() and delete() cookies. Use httpOnly, secure and sameSite to keep them safe.
TL;DR
- Middleware =
onRequest(context, next)insrc/middleware.ts. Runs around every request. - next() = run the page. Change the response after it.
- sequence(a, b) = run several middleware in order.
- context.redirect() / context.rewrite() = answer early.
- locals = per-request data. Middleware writes, pages read
Astro.locals. - Cookie = small data in the browser, sent with every request.
- Read =
cookies.get(name)?.value / .number() / .boolean() / .json(),cookies.has(name). - Write =
cookies.set(name, value, options),cookies.delete(name, { path }). - Options =
path,maxAge,httpOnly,secure,sameSite,domain.
Common mistakes
| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
Not returning next() | Calling it is enough | return next() or return its response | The page gets no response |
| Middleware in the wrong place | Any file name works | src/middleware.ts exporting onRequest | It never runs |
| Setting a cookie on a static page | Static pages have requests | Set cookies on on-demand routes | Error: cookies cannot be set |
Deleting with a different path | delete() finds every copy | Use the same path as set() | The cookie stays |
| Secrets in a cookie | Cookies are private | Store an ID, keep data on the server | Visitors can read or change it |
No httpOnly on a session cookie | Scripts need it | Use httpOnly: true | Injected scripts can steal it |
Check Yourself
Exercises
What to Remember
- Middleware in
src/middleware.tsruns around every request.next()runs the page. sequence()chains small middleware.localspasses data to pages.- Middleware can redirect or rewrite before the page runs.
- Cookies live in the browser. Read with
get(), write withset(), remove withdelete(). - Use
httpOnly,secureandsameSite, and never trust a cookie blindly.
Next: Sessions, where data stays on the server and only an ID lives in a cookie.