Performance: Self-hosting with Node.js
This affects the server response time and initial page load speed by controlling how the Next.js app is served and assets are delivered.
import { createServer } from 'http'; import { parse } from 'url'; import next from 'next'; const app = next({ dev: false }); const handle = app.getRequestHandler(); app.prepare().then(() => { createServer((req, res) => { const parsedUrl = parse(req.url, true); handle(req, res, parsedUrl); }).listen(3000, () => { console.log('> Ready on http://localhost:3000'); }); });
const express = require('express'); const next = require('next'); const app = next({ dev: true }); const handle = app.getRequestHandler(); app.prepare().then(() => { const server = express(); server.all('*', (req, res) => { return handle(req, res); }); server.listen(3000, () => { console.log('> Ready on http://localhost:3000'); }); });
| Pattern | Server Response | Bundle Size | LCP Impact | Verdict |
|---|---|---|---|---|
| Dev mode self-hosting | Slow (200-500ms delay) | Large (unminified bundles) | High delay | [X] Bad |
| Prod mode self-hosting | Fast (50-100ms delay) | Small (minified bundles) | Low delay | [OK] Good |
next start runs the app in production mode with Node.js.next dev is for development, npm run build builds but doesn't start, node next is invalid.import next from 'next';
import http from 'http';
const app = next({ dev: false });
const handle = app.getRequestHandler();
app.prepare().then(() => {
http.createServer((req, res) => {
handle(req, res);
}).listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
});import next from 'next';
import http from 'http';
const app = next({ dev: true });
const handle = app.getRequestHandler();
app.prepare().then(() => {
http.createServer((req, res) => {
handle(req, res);
}).listen(3000);
});
What is the likely cause of the issue?listen method works without a callback, but missing callback means no confirmation message that the server started.handle(req, res) ensures the log happens before Next.js processes the request.import next from 'next';
import http from 'http';
const app = next({ dev: false });
const handle = app.getRequestHandler();
app.prepare().then(() => {
http.createServer((req, res) => {
console.log(`Request URL: ${req.url}`);
handle(req, res);
}).listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
}); calls handle after logging, letting Next.js handle the response properly. Other options either log after response or do not call handle.import next from 'next';
import http from 'http';
const app = next({ dev: false });
const handle = app.getRequestHandler();
app.prepare().then(() => {
http.createServer((req, res) => {
console.log(`Request URL: ${req.url}`);
handle(req, res);
}).listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
}); includes a listen callback to confirm server is running, which is good practice.Pass the test and this pattern moves unknown