Tutorials on Nodejs

Learn about Nodejs from fellow newline community members!

  • React
  • Angular
  • Vue
  • Svelte
  • NextJS
  • Redux
  • Apollo
  • Storybook
  • D3
  • Testing Library
  • JavaScript
  • TypeScript
  • Node.js
  • Deno
  • Rust
  • Python
  • GraphQL
  • React
  • Angular
  • Vue
  • Svelte
  • NextJS
  • Redux
  • Apollo
  • Storybook
  • D3
  • Testing Library
  • JavaScript
  • TypeScript
  • Node.js
  • Deno
  • Rust
  • Python
  • GraphQL
NEW

Exploring Modern Web Development Stack: Fullstack TypeScript with TailwindCSS and tRPC Using PostgreSQL

This article will dive into a development stack that is gaining traction due to its robustness and adaptability. We'll explore what sets this stack apart from well-established stacks like MEAN and MERN, and why developers should consider its adoption. The cutting-edge stack we're exploring comprises several technologies that, although not entirely new, are combined uniquely to boost development efficiency and code quality. This modern stack includes: This stack facilitates enhanced type safety, seamless management of monorepo structures, shared configurations across packages, and a streamlined frontend setup with Vite, React, and Tailwind. Moreover, this stack enables database migration with raw SQL and access via knex.js , using tRPC as the API layer and Koa as the backend framework. Although this modern stack shares some technologies with MEAN and MERN, it distinguishes itself with the inclusion of TypeScript , TailwindCSS , Koa , Knex , and tRPC . These additions bolster type safety with TypeScript, reduce plumbing code requirement with tRPC, and optimize the use of PostgreSQL. The components of this stack are interchangeable, providing developers with the freedom to substitute any part of the stack with alternatives that better cater to their needs. This adaptability and interchangeability lead to a slightly more complex setup process than MEAN and MERN, but the trade-off is justifiable for the resulting control and flexibility it offers. This advanced stack is suitable for developers who: The strength of this stack lies in its capability to build type-safe full-stack applications, establish robust and scalable application architectures in a monorepo, and use the database as the underlying source of truth. It allows for database migration using raw SQL and capitalizes on all the sophisticated features that PostgreSQL offers. The modern stack, Fullstack TypeScript with TailwindCSS and tRPC Using PostgreSQL , presents a distinctive mix of technologies that boost development efficiency, code quality, and type safety. It may demand more setup effort than traditional stacks, but the resultant flexibility and control over the components make it a formidable contender for your next project. For an extensive exploration of this stack, consider Kristian Dupont’s course Fullstack TypeScript with TailwindCSS and tRPC Using Modern Features of PostgreSQL . The course provides a detailed understanding of the stack and its benefits, making it a precious resource for developers keen on exploring this modern stack.

Introduction to using PostgreSQL with NodeJS: A Beginner's Guide

Are you ready to dive into the world of powerful database management with PostgreSQL and NodeJS? This guide is designed for beginners who want to understand how to use PostgreSQL in their NodeJS projects. Whether you're new to databases or looking to expand your skills, this tutorial will help you get started with confidence. In this guide, we'll cover: By the end of this tutorial, you'll have a solid foundation for building applications with PostgreSQL and NodeJS. For a more visual representation and in-depth details, you may refer to this video tutorial by me, Kristian Dupont, on \newline’s YouTube channel. Before we begin, you'll need to have PostgreSQL installed on your system. Here are two ways to do it: If you prefer using Docker, you can run PostgreSQL in a container with this one-liner: This command will: Now that we have PostgreSQL installed, let's set up our NodeJS project and connect to the database. Let's create a simple Koa server that we'll use to handle our API requests. Create a new file named server.mjs : Now, let's implement three endpoints for basic CRUD operations on a users table. First, let's create our users table. Run this SQL command in your PostgreSQL client: Now, let's add our routes to server.mjs : These routes allow you to: At this point, you should be able to start your server with the following command line: It should print that the server is running on port 3000. You can try it out by opening this route in a browser: http://localhost:3000/users — which should give you an empty array. Use a tool like cUrl or Postman to try out the POST route and see that you can create users in your database. The guide above forms part of a broader context, which includes working with a monorepo , setting up npm workspaces in monorepos , sharing configurations across packages, setting up the frontend with Vite , React , and Tailwind , and more. The full stack comprises the following technologies: This development stack provides end-to-end type safety, a greater confidence level when refactoring, and the ability to work with the database using plain SQL while still maintaining a type-safe architecture. Mastering PostgreSQL doesn't have to be intimidating. With this guide as a base, you can embark on your journey towards advanced database management using a full stack of contemporary technologies. To enhance your skills further, check out my course Fullstack Typescript with TailwindCSS and tRPC Using Modern Features of PostgreSQL . Happy learning!

I got a job offer, thanks in a big part to your teaching. They sent a test as part of the interview process, and this was a huge help to implement my own Node server.

This has been a really good investment!

Advance your career with newline Pro.

Only $30 per month for unlimited access to over 60+ books, guides and courses!

Learn More

Row Level Security in NodeJS

If you are using PostgreSQL for storing data of multiple users, you might want to apply row-level security, or RLS. It’s good practice even if you are manually writing all the queries you send to your database but it’s especially important if you have any type of LLM or similar generating queries for you! Let’s create a trivial data model. Users and items, whatever that might be. Each item belongs to a user. Now, per default, if you ask the database about any users items, it will just tell you. By introducing RLS, you can limit what the responses will be to add a layer of protection. Even if you should create a buggy query, you will not accidentally get the items belonging to someone else, just like you cannot accidentally change or delete items belonging to someone else. We do that like this: Note that app.curren user id isn’t something PostgreSQL knows about per default, it’s a variable that we have introduced. Now basically, we need to execute SET app.curren user id = '(user_id)' , before making some user-specific query. Or if you have a transaction, you could use SET LOCAL which will make the transaction scope function as “auth scope” as well. Depending on your setup, there are going to be different ways to set the app.curren user id setting. In this example, I will assume a setup based on Express or similar, and Knex for creating queries, but the pattern can easily be changed to fit whatever your setup requires. The app.curren user id needs to be set only once per session. This session variable is local to the database connection, meaning each connection has its own set of session variables. When using Knex or similar to execute a query, it acquires a connection from the pool. The session variables set in that connection are isolated from other connections. Now, with Express and similar frameworks, you will typically use the context variable to store state that is related to a given request. You might already have some code in middleware that checks a token and fetches the corresponding user from the database. What we could do is to put a knex instance into this context, and make sure that instance has set the user id. However, this forces us to do quite a bit of “prop drilling” as we need to pass this instance around as a parameter to any function that needs to access the database. What we can do instead is to use a class called AsyncLocalStorage which allows us to store state related to a specific async context. This is similar to “thread-local storage” in other languages, only we don’t have threads in NodeJS but async contexts. Apply the dbMiddleware to your server whereever you set up other middleware, and now you can use the getKnexInstance to get the authenticated database connection. Here is an example of a very simple server: As you can see, this endpoint selects every items row. I don’t recommend this, you should still create your queries as you normally do, but even if you released this, no items belonging to other users would leak anywhere. Mastering Row Level Security in NodeJS doesn't have to be intimidating. With this guide as a base, you can embark on your journey toward something bigger. To enhance your skills further, check out my course Fullstack Typescript with TailwindCSS and tRPC Using Modern Features of PostgreSQL . Happy learning!

Deploying a Node.js and PostgreSQL Application to Heroku

Serving a web application to a global audience requires deploying, hosting and scaling it on reliable cloud infrastructure. Heroku is a cloud platform as a service (PaaS) that supports many server-side languages (e.g., Node.js, Go, Ruby and Python), monitors application status in a beautiful, customizable dashboard and maintaining an add-ons ecosystem for integrating tools/services such as databases, schedulers, search engines, document/image/video processors, etc. Although it is built on AWS, Heroku is simpler to use compared to AWS. Heroku automatically provisions resources and configures low-level infrastructure so developers can focus exclusively on their application without the additional headache of manually setting up each piece of hardware and installing an operating system, runtime environment, etc. When deploying to Heroku, Heroku's build system packages the application's source code and dependencies together with a language runtime using a buildpack and slug compiler to generate a slug , which is a highly optimized and compressed version of your application. Heroku loads the slug onto a lightweight container called a dyno . Depending on your application's resource demands, it can be scaled horizontally across multiple concurrent dynos. These dynos run on a shared host, but the dynos responsible for running your application are isolated from dynos running other applications. Initially, your application will run on a single web dyno, which serves your application to the world. If a single web dyno cannot sufficiently handle incoming traffic, then you can always add more web dynos. For requests exceeding 500ms to complete, such as uploading media content, consider delegating this expensive work as a background job to a worker dyno. Worker dynos process these jobs from a job queue and run asynchronously to web dynos to free up the resources of those web dynos. Below, I'm going to show you how to deploy a Node.js and PostgreSQL application to Heroku. First, let's download the Node.js application by cloning the project from its GitHub repository: Let's walkthrough the architecture of our simple Node.js application. It is a multi-container Docker application that consists of three services: an Express.js server, a PostgreSQL database and pgAdmin. As a multi-container Docker application orchestrated by Docker Compose , the PostgreSQL database and pgAdmin containers are spun up from the postgres and dpage/pgadmin4 images respectively. These images do not need any additional modifications. ( docker-compose.yml ) The Express.js server, which resides in the api subdirectory, connects to the PostgreSQL database via the pg PostgreSQL client. The module api/lib/db.js defines a Database class that establishes a reusable pool of clients upon instantiation for efficient memory consumption. The connection string URI follows the format postgres://[username]:[password]@[host]:[port]/[db_name] , and it is accessed from the environment variable DATABASE_URL . Anytime a controller function (the callback argument of the methods app.get , app.post , etc.) calls the query method, the server connects to the PostgreSQL database via an available client from the pool. Then, the server queries the database, directly passing the arguments of the query method to the client.query method. Once the database sends the requested data back to the server, the client is released back to the pool, available for the next request to use. Additionally, there's a getAllTables method for retrieving low-level information about the tables available in our PostgreSQL database. In this case, our database only contains a single table: cp_squirrels . ( api/lib/db.js ) The table cp_squirrels is seeded with records from the 2018 Central Park Squirrel Census dataset downloaded from the NYC Open Data portal. The dataset, downloaded as a CSV file, contains the fields obs_date (observation date) and lat_lng (coordinates of observation) with values that are not compatible with the PostgreSQL data types DATE and POINT respectively. Instead of directly copying the contents of the CSV file to the cp_squirrels table, copy from the output of a GNU awk ("gawk") script. This script... ( db/create.sql ) Upon the initialization of the PostgreSQL database container, this SQL file is ran by adding it to the docker-entrypoint-initdb.d directory. ( db/Dockerfile ) This server exposes a RESTful API with two endpoints: GET /tables and POST /api/records . The GET /tables endpoint simply calls the db.getAllTables method, and the POST /api/records endpoint retrieves data from the PostgreSQL database based on a query object sent within the incoming request. To bypass CORS restrictions for clients hosted on a different domain (or running on a different port on the same machine) sending requests to this server, all responses must have the Access-Control-Allow-Origin header set to the allowable domain ( process.env.CLIENT_APP_URL ) and the Access-Control-Allow-Headers header set to Origin, X-Requested-With, Content-Type, Accept . ( api/index.js ) Notice that the Express.js server requires three environment variables: CLIENT_APP_URL , PORT and DATABASE_URL . These environment variables must be added to Heroku, which we will do later on in this post. The Dockerfile for the Express.js server instructs how to build the server's Docker image based on its needs. It automates the process of setting up and running the server. Since the server must run within a Node.js environment and relies on several third-party dependencies, the image must be built upon the node base image and install the project's dependencies before running the server via the npm start command. ( api/Dockerfile ) However, because the filesystem of a Heroku dyno is ephemeral , volume mounting is not supported. Therefore, we must create a new file named Dockerfile-heroku that is dedicated only to the deployment of the application to Heroku and not reliant on a volume. ( api/Dockerfile-heroku ) Unfortunately, you cannot deploy a multi-container Docker application via Docker Compose to Heroku. Therefore, we must deploy the Express.js server to a web dyno with Docker and separately provision a PostgreSQL database via Heroku Postgres add-on . To deploy an application with Docker, you must either: For this tutorial, we will deploy the Express.js server to Heroku by building a Docker image with heroku.yml and deploying this image to Heroku. Let's create a heroku.yml manifest file inside of the api subdirectory. Since the Express.js server will be deployed to a web dyno, we must specify the Docker image to build for the application's web process, which the web dyno belongs to: ( api/heroku.yml ) Because our api/Dockerfile already has a CMD instruction, which specifies the command to run within the container, we don't need to add a run section. Let's add a setup section, which defines the environment's add-ons and configuration variables during the provisioning stage. Within this section, add the Heroku PostgreSQL add-on. Choose the free " Hobby Dev " plan and give it a unique name DATABASE . This unique name is optional, and it is used to distinguish it from other Heroku PostgreSQL add-ons. Fortunately, once the PostgreSQL database is provisioned, the DATABASE_URL environment variable, which contains the database connection information for this newly provisioned database, will be made available to our application. Check if your machine already has the Heroku CLI installed. If not yet installed, then install the Heroku CLI. For MacOSX, it can be installed via Homebrew: For other operating systems, follow the instructions here . After installation, For the setup section of the heroku.yml manifest file to be recognized and used for creating a Heroku application, switch to the beta update channel and install the heroku-manifest plugin: Without this step, the PostgreSQL database add-on will not be provisioned from the heroku.yml manifest file. You would have to manually provision the database via the Heroku dashboard or heroku addons:create command. Once installed, close out the terminal window and open a new one for the changes to take effect. Note : To switch back to the stable update stream and uninstall this plugin: Now, authenticate yourself by running the follow command: Note : If you want to remain within the terminal, as in entering your credentials directly within the terminal, then add the -i option after the command. This command prompts you to press any key to open a login page within a web browser. Enter your credentials within the login form. Once authenticated, Heroku CLI will automatically log you in. Within the api subdirectory, create a Heroku application with the --manifest flag: This command automatically sets the stack of the application to container and sets the remote repository of the api subdirectory to heroku . When you visit the Heroku dashboard in a web browser, this newly created application is listed under your "Personal" applications: Set the configuration variable CLIENT_APP_URL to a domain that should be allowed to send requests to the Express.js server. Note : The PORT environment variable is automatically exposed by the web dyno for the application to bind to. As previously mentioned, once the PostgreSQL database is provisioned, the DATABASE_URL environment variable will automatically be exposed. Under the application's "Settings" tab in the Heroku Dashboard, you can find all configuration variables set for your application under the "Config Vars" section. Create a .gitignore file within the api subdirectory. ( api/.gitignore ) Commit all the files within the api subdirectory: Push the application to the remote Heroku repository. The application will be built and deployed to the web dyno. Ensure that the application has successfully deployed by checking the logs of this web dyno: If you visit https://<application-name>.herokuapp.com/tables in your browser, then a successful response is returned and printed to the browser. In case the PostgreSQL database is not provisioned, manually provision it using the following command: Then, restart the dynos for the DATABASE_URL environment variable to be available to the Express.js server at runtime. Deploy your own containerized applications to Heroku!

Thumbnail Image of Tutorial Deploying a Node.js and PostgreSQL Application to Heroku