Spin up a Node.js/Express server and a Postgres database

Quick steps to create a Node.js, Express, and Postgres playground.

Sometimes I'm experimenting with a quick idea and I want to spin up a server and database for it on localhost. There are a handful of quick steps I take out of the gate to get up and running with Node.js, Express, and Postgres.

For the remainder of this post, I'll show what those steps are. I'll skip in-depth explanations, and focus on the setup.

If you follow the steps, by the end, you'll be able to make an API call via cURL or Postman to a server on localhost, which will in turn read from or write to the database and return the result to your client.

I will note here at the outset that the end result is a playground for experimentation, and in no way is it production-ready.

I hope this is helpful. Happy hacking!

Create a folder

Any folder name will do:

mkdir server && cd server && git init

Any CLI commands you see below all happen in this folder, the root of the project.

Express generator

Generate your Express server (with a default .gitignore file and without a view engine):

npx express-generator --git --no-view

Done. We used npx because we won't need express-generator again. Since I only need this module once per project, I prefer not to install it globally.

Nodemon

Add nodemon to your project to auto-restart your server when you edit files:

npm i -S nodemon

Then, in package.json, modify the default start script to use nodemon instead of node:

"scripts": {
    "start": "nodemon ./bin/www"
},

This step isn't crucial to getting set up, but is a solid lifestyle upgrade, so I prefer to go ahead and do it early.

Sequelize

This section contains the most steps, but shouldn't take much time to do.

Initialize sequelize

Add sequelize, pg, and sequelize-cli to your project, then initialize your sequelize project.

npm i -S sequelize pg
npm i -D sequelize-cli
npx sequelize init

I install sequlize-cli as a dev dependency locally (as opposed to running npx without the install) because I use this CLI a number of times over the course of a project, and I want the CLI to be there even if I'm not connected to the internet.

Configure your database

The sequelize CLI created a config/config.json file. Switch out the content of the file with the following (you can change the name in the database fields to whatever you prefer):

{
  "development": {
    "username": "",
    "password": "",
    "database": "node_server_database_development",
    "dialect": "postgres",
    "protocol": "postgres"
  },
  "test": {
    "username": "",
    "password": "",
    "database": "node_server_database_test",
    "dialect": "postgres",
    "protocol": "postgres"
  },
  "production": {
    "username": "",
    "password": "",
    "database": "node_server_database_production",
    "dialect": "postgres",
    "protocol": "postgres",
    "use_env_variable": "DATABASE_URL"
  }
}

Timely reminder: this is not prod-ready, but fine for noodling around on localhost.

Create your database

A short one-liner:

npx sequelize db:create

If you run into issues here, check the config/config.json file in the previous step.

Generate a model

Make, as a random example, a User model:

npx sequelize model:generate --name User --attributes username:string,email:string,password:string

For some reason, model generation via CLI is documented only in the sequelize CLI's FAQ. Since you'll most likely create more models, you may want to keep that link handy.

Connect and sync the database on server start

Open /bin/www and add the sequelize instance that was generated by the CLI as a dependency:

const sequelize = require("../models").sequelize;

Then in the same file, find the server.listen(port) line, and replace it with this:

sequelize
  .sync({ alter: true }) // Not recommended for production use.
  .then(() => {
    server.listen(port);
  })
  .catch((err) => {
    console.log(err);
  });

You can learn more about the .sync() method in the sequelize docs. I use the alter option locally because I may end up revising my models frequently, and this will keep my db tables up-to-date with my latest models.

Express routes

Almost there! Lastly, throw a couple of basic routes into routes/users.js:

const express = require("express");
const router = express.Router();
const { User } = require("../models");

router.get("/", async (req, res, next) => {
  try {
    const users = await User.findAll();
    res.json(users);
  } catch (error) {
    next(error);
  }
});

router.post("/", async (req, res, next) => {
  try {
    const user = await User.create(req.body);

    res.json(user);
  } catch (error) {
    next(error);
  }
});

module.exports = router;

You've got a route for getting all users, and a route for creating a single user.

Since these routes are in the routes/users.js file, the endpoints will be accessible at localhost:3000/users (via GET and POST methods, respectively).

We're done with the setup!

Try it

Start up your server:

npm start

Now you can try hitting the API with cURL with a request to create a user:

curl --location --request POST 'localhost:3000/users/' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'username=ash' \
--data-urlencode 'email=ash@node.server' \
--data-urlencode 'password=nodeserverftw'

You should get back a response that looks like this:

{"id":1,"username":"ash","email":"ash@node.server","password":"nodeserverftw","updatedAt":"2020-07-30T00:25:42.226Z","createdAt":"2020-07-30T00:25:42.226Z"}

Or you can get all users:

curl --location --request GET 'localhost:4000/users/' --header 'Content-Type: application/x-www-form-urlencoded'  

Which returns an array containing the single user we just created:

[{"id":1,"username":"ash","email":"ash@node.server","password":"nodeserverftw","createdAt":"2020-07-30T01:28:03.032Z","updatedAt":"2020-07-30T01:28:03.032Z"}]

Your Node.js, Express, and Postgres playground is ready. Have fun!


There are lot of ways to go about spinning up a local project, surely much better ones if you are on the path to building a production server!

If you're looking for something simple and quick, I hope this setup is helpful.