docs/migration-v2-to-v3.md
Koa v3 requires Node.js v18.0.0 or higher.
As announced in Koa v2.x, support for the old middleware signature (generator functions) has been removed in v3.
If you were still using generator middleware with koa-convert, you'll need to update all middleware to use async functions or functions that return promises.
// Old way (using koa-convert with generator middleware)
const convert = require('koa-convert');
app.use(convert(function* (next) {
const data = yield fetchData();
yield next;
this.body = data;
}));
// New way (using async/await)
app.use(async (ctx, next) => {
const data = await fetchData();
await next();
ctx.body = data;
});
Koa v3 updates http-errors to v2.0.0, which changes the signature of ctx.throw():
// Old format in Koa v2.x
ctx.throw(status, message, properties)
// New format in Koa v3.x
ctx.throw(status, error, properties)
See the http-errors documentation for more details.
The res.redirect('back') method has been removed. Instead, use the new ctx.back() method:
// Old way in Koa v2.x
ctx.response.redirect('back')
// New way in Koa v3.x
ctx.back()
Node's querystring module has been replaced with URLSearchParams. This should be mostly transparent to users, but might cause subtle differences in query string parsing.
// Old way (Koa v2.x using querystring)
const qs = require('querystring');
app.use(async (ctx, next) => {
const query = qs.parse(ctx.querystring);
// query['user[]'] = ['john', 'jane']
// query['items[0]'] = 'book'
await next();
});
// New way (Koa v3.x using URLSearchParams)
app.use(async (ctx, next) => {
const query = new URLSearchParams(ctx.querystring);
// query.getAll('user') => ['john', 'jane']
// query.get('items') => 'book'
await next();
});
Koa v3 adds support for AsyncLocalStorage, which allows you to access the current context from anywhere in your application:
// Enable AsyncLocalStorage
const app = new Koa({ asyncLocalStorage: true })
app.use(async (ctx, next) => {
callSomeFunction()
await next()
})
function callSomeFunction() {
// Access the current context
const ctx = app.currentContext
// Do something with ctx
}
You can also pass your own AsyncLocalStorage instance:
const { AsyncLocalStorage } = require('async_hooks')
const asyncLocalStorage = new AsyncLocalStorage()
const app = new Koa({ asyncLocalStorage })
app.use(async (ctx, next) => {
callSomeFunction()
await next()
})
function callSomeFunction() {
// Access the current context
const ctx = asyncLocalStorage.getStore()
// Do something with ctx
}
Koa v3 adds support for Web WHATWG standards, including:
Blob objects as response bodiesReadableStream objects as response bodiesResponse objects as response bodiesapp.use(async ctx => {
// Using a Blob
ctx.body = new Blob(['Hello World'], { type: 'text/plain' })
// Using a ReadableStream
ctx.body = new ReadableStream({
start(controller) {
controller.enqueue('Hello World')
controller.close()
}
})
// Using a Response object
ctx.body = new Response('Hello World', {
headers: { 'Content-Type': 'text/plain' }
})
})
Update your Node.js version to v18.0.0 or higher
Update all generator middleware to use async functions:
// Old way (generator middleware)
app.use(function* (next) {
const start = Date.now()
yield next
const ms = Date.now() - start
console.log(`${this.method} ${this.url} - ${ms}ms`)
})
// New way (async middleware)
app.use(async (ctx, next) => {
const start = Date.now()
await next()
const ms = Date.now() - start
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
})
Update any calls to ctx.throw() to use the new signature:
// Old way (Koa v2.x)
ctx.throw(404, 'User not found', { user: 'john' });
// New way (Koa v3.x)
const error = new Error('User not found');
ctx.throw(404, error, { user: 'john' });
// You can also throw HTTP errors directly
const createError = require('http-errors');
ctx.throw(createError(404, 'User not found', { user: 'john' }));
Replace ctx.response.redirect('back') with ctx.back()
Test your application thoroughly to ensure compatibility