CodeNewbie Community 🌱

James Wallis
James Wallis

Posted on • Originally published at on

How to use with Next.js, Express and TypeScript (ES6 import instead of require statements)

I'm currently working on a TypeScript project that is using to communicate between a Next.js frontend and a custom Express server backend.

While setting up I struggled to find documentation explaining how you could set up in a TypeScript project using the ES6 import syntax rather than require. It was even more difficult to find anything that explained how it should all fit together with Next.js.

And so this post was born...

If you're starting from scratch...

If you want to make a TypeScript/Express custom server Next.js project, mine was created by combining the custom Express Server example and custom TypeScript Server example located in the Next.js repository.

First I created the project using the command npx create-next-app --example custom-server-typescript to create the custom TypeScript server. Then I retrofitted Express into it by looking at the custom Express server example. The resulting server.ts is at the bottom of this post.

Why didn't I follow another example?

Most of the examples I saw online want you to do something like the following:

import express from 'express';

const app = express();
const server = require('http').Server(app);
const io = require('')(server);

Enter fullscreen mode Exit fullscreen mode

Enter fullscreen mode Exit fullscreen mode

But I didn't want two or any random require statements in my TypeScript code if I thought they could be avoided.

My server.ts with only ES6 import

The dependencies you need (In addition to Next.js/React/TypeScript):

npm install -s express @types/express socket-io

Enter fullscreen mode Exit fullscreen mode

Enter fullscreen mode Exit fullscreen mode

The code you've been waiting for:

import express, { Express, Request, Response } from 'express';
import * as http from 'http';
import next, { NextApiHandler } from 'next';
import * as socketio from '';

const port: number = parseInt(process.env.PORT || '3000', 10);
const dev: boolean = process.env.NODE_ENV !== 'production';
const nextApp = next({ dev });
const nextHandler: NextApiHandler = nextApp.getRequestHandler();

nextApp.prepare().then(async() => {
    const app: Express = express();
    const server: http.Server = http.createServer(app);
    const io: socketio.Server = new socketio.Server();

    app.get('/hello', async (_: Request, res: Response) => {
        res.send('Hello World')

    io.on('connection', (socket: socketio.Socket) => {
        socket.emit('status', 'Hello from');

        socket.on('disconnect', () => {
            console.log('client disconnected');

    app.all('*', (req: any, res: any) => nextHandler(req, res));

    server.listen(port, () => {
        console.log(`> Ready on http://localhost:${port}`);

Enter fullscreen mode Exit fullscreen mode

Enter fullscreen mode Exit fullscreen mode

server.ts explanation

The main difference between my server.ts and the ones produced by the Next.js examples is the use of the http module to run the server whereas before Express ran it. This is required so that can attach to the server once it's setup.

Additional changes:

  • Changed app to be nextApp so that it is clearer that it was a next app, also changed handler to nextHandler for the same reason. In addition, it's the convention to use the app variable with Express.
  • Used http.CreateServer() rather than const server = require("http").Server(app); to create the HTTP server.
  • Used io.attach() to attach to the HTTP server rather than using require e.g. const io = require("")(server);.


This post demonstrates how to use with a Next.js custom server using ES6 import rather than require.

If this post helped you drop me a reaction! Found something I could improve? Let me know in the comments.

Thanks for reading!

Top comments (0)