Setting up a Free Postgres Database in Heroku w/ PgAdmin

Step 1: Log into Heroku

Step 2: Create a New App

Create a new Heroku app by either clicking “Create a new app” in the center of the screen or “New” at the top right of the screen.

Choose an App Name and the Region (either the US or Europe) for your new app. The name can be anything you want. Then, just click the Create app button.

Step 3: Add a PostgreSQL Database

To attach a PostgreSQL database to the blank app you just made, you need to go to the Resources tab in the header of the new app’s dahsboard. Then type Heroku Postgres into the Add-ons search field. When shown, select the suggested Heroku Postgres add-on from the dropdown:

The next popup asks you to choose a pricing plan for the database. Select the Hobby Dev – Free plan and click Provision.

Now your PostgreSQL database is up !

Step 4: Get Heroku DB Information

To find the credentials and the connection URL for the PostgreSQL database, make sure you’re still in the Resources tab and click on the Heroku Postgres resource we just added.

That should bring you to this screen:

Select the Settings tab in the header of that screen. You will be navigated to a page where Here, you can click the View Credentials button to see the credentials of your PostgreSQL database.

You will need these values to input into your PgAdmin interface

Step 5: Configure PgAdmin w/ Heroku DB Credentials

Open up PgAdmin

Right-click on Servers at the very top of the left-side panel

Choose Create > Serve

Fill out the new server form with all of the corresponding information from the Heroku View Credentials page.

After you save the new server, it will become populated with a huge list of databases. You will not have access to any of them except the one with your Database name from Heroku. Scroll through and find this one.

Then, as you would with any other PgAdmin database, go to Schemas > public > Create new Table. Populate this table with the fields you want.

You’re all set.

How to Execute a Python Script in a Node.js Project

This tutorial assumes that you’ve already set up a basic Node.js project with Express. I have other tutorials explaining how to do this if you don’t know how.

First, create a new python file in your Node project directory. I will call mine In, I will write a simple Python print statement to test.

print("Hello world")

In my main JavaScript file, I’m going to add the bolded line:

const express = require('express');
const { spawn } = require('child_process');

const app = express();

app.get('/', (req, res) => {
   console.log('Hello world');

app.listen(4000, console.log('Server started on port 4000'));

In the code above, we set up a basic Express app with one get router. Pay attention to the bolded line:

const { spawn } = require('child_process');

Next, we will use the new spawn class that we imported with this line from the child_process library.

In the get router, add the following lines:

app.get('/', (req, res) => {
   const childPython = spawn('python', ['']);

   childPython.stdout.on('data', (data) => {
      console.log(`stdout: ${data}`)

   childPython.stderr.on('data', (data) => {
      console.error(`stderr: ${data}`);

   childPython.on('close', (code) => {
      console.log(`child process exited with code ${code}`);

In the above code, spawn a new child_process with parameters ‘python‘ and ‘‘. We set this to an object called childPython:

const childPython = spawn('python', ['']);

The first parameter is the program we want to call and the second is an array of strings that will use the python program. It is the same command if you wanted to write it in a shell to run the python ''

The first event is:

childPython.stdout.on('data', (data) => {
      console.log(`stdout: ${data}`)

The data argument that we are receiving from the callback function will be the output of the Python code we wrote in We could also get access to the outputs this way. In the code below, we have to either return or console.log the dataToSend.

python.stdout.on('data', function (data) {
   dataToSend = data.toString();

If this event fails, the error event will be called:

childPython.stderr.on('data', (data) => { 
    console.error(`stderr: ${data}`);

This is the final event. The close event is emitted (run) when the stdio streams of a child process have been closed:

childPython.on('close', (code) => {
   console.log(`child process exited with code ${code}`);

Here’s another example of a very basic program. This program will generate a random number between 0 and 9 (inclusive):

The contents of file:

import random 

def generate():
    return random.randint(0, 9)


The contents of index.js file:

const express = require('express');
const { spawn } = require('child_process');

const childPython = spawn('python', ['']);

childPython.stdout.on('data', (data) => {
    console.log(`The new random number is: ${data}`)

childPython.stderr.on('data', (data) => {
    console.error(`There was an error: ${data}`);

childPython.on('close', (code) => {
    console.log(`child process exited with code ${code}`);

const app = express();

const PORT = process.env.PORT || 4000;
app.listen(PORT, console.log(`Server started on port ${PORT}`));

The output should look something like this:

How to Build a Node.js Project for Beginners

First, make sure you have Node installed. I’m not going to show how to do that in those tutorial. For developers that already know how to use Node, this tutorial can serve as a guide to help jog your memory whenever you forget all the steps to building a new Node.js project.

Once you have Node installed, you can write these commands in Terminal to get started:

mkdir folder-name    (create a new folder)
npm init             (initialize Node Package Manager)
touch index.js       (create server file)

For the npm init step, it will make you click through a bunch of prompts/set-up questions to set up NPM in your folder.

For your server file, it doesn’t matter what it’s name is as long as you make sure it has the same name as the one you defined in the NPM initialization questions.

In Terminal within your project directory, add these NPM packages to your project using the command npm i or npm install

npm i express         (install express - a Node web framework)
npm i -D nodemon      (install nodemon as a dev dependency)

Open up your server file (index.js) in a code editor (I prefer Visual Studio Code) and type this Node code:

const express = require('express');

const app = express();

const PORT = process.env.PORT || 4000;

app.listen(PORT, console.log(`Server started on port ${PORT}`));

The Express framework is the most popular Node backend web framework by far and it will make working with Node for the web 100x easier.

To run this and make sure it works, type this command in your Terminal (make sure your in your project directory):

nodemon index.js

The Terminal should output the string “Server started on port 4000” (or port 5000, 6000, etc. based on what you put in your code).

This means that the project is running on the specified port on your localhost.

Sequelize with PostgreSQL with Node

Import the Sequelize module into your Node project

npm i sequelize

Add the specific database driver to coincides with the SQL DBMS that you are using:

npm i --save pg pg-hstore   

Connect to the database in your Node application

Option 1: Passing a connection URI

const sequelize = new Sequelize('postgres://') 

module.exports = sequelize;

Option 2: Passing parameters separately (other dialects)

const sequelize = new Sequelize('database', 'username', 'password', {    
   host: 'localhost', 
   dialect: 'postgres'

module.exports = sequelize;

Test the connection

try { 
   await sequelize.authenticate(); 
   console.log('Connection has been established successfully.'); 
} catch (error) { 
   console.error('Unable to connect to the database:', error); 

Create a new model

The db variable is imported from the Sequelize connection above (Opt 1 or 2) which we are assuming is in a separate file.

const Sequelize = require('sequelize');
const db = require('../config/database');

const Person = db.define('gig', {
   name: {
      type: Sequelize.STRING
   age: {
      type: Sequelize.INTEGER
   description: {
      type: Sequelize.STRING

module.exports = Person;

Start making Sequelize queries in server routes

The beauty of Sequelize is that it allows you to use object-oriented syntax to make queries to relational/SQL databases.

app.get('/', (req, res) =>
      .then(people => console.log(people))
      .catch(err => console.log(err)));

Find and kill process locking a port on Mac

This error was caused when I tried to locally run a server on a port that was already being used by another server that I had previously left running and forgot to turn off.

This command will show you all the process(es) running on a port and their PIDs

sudo lsof -i :3000

Kill the process by replacing <PID> with the process’ PID number

kill -9 <PID>

Upload Images to AWS S3 from Node Server w/ Multer

  1. Create a bucket
    1. (Sign in to console) Sign in to the AWS Management Console and open the Amazon S3 console at
    2. Choose Create Bucket
    3. In Bucket name,  enter a DNS-compliant name for your bucket.
    4. In Region, choose the AWS Region where you want the bucket to reside.
    5. In Bucket settings for Block Public Access, keep the values set to the defaults. They will be private for now. We will change them to public later.
    6. Choose Create bucket.

2. Get security credentials

3. Install dependencies to Node project

npm i --save aws-sdk multer multer-s3

4. Set up the file upload middleware with multer and AWS-SDK

const aws = require('aws-sdk');
const multer = require('multer');
const multerS3 = require('multer-s3');

const config = require('../config');

   secretAccessKey: config.get('AWS_SECRET_ACCESS'),
   accessKeyId: config.get('AWS_ACCESS_KEY'),
   region: 'us-east-1'

const s3 = new aws.S3();

const upload = multer({
   storage: multerS3({
      bucket: 'bucket-name',
      acl: 'public-read',
      key: function (req, file, cb) {

module.exports = upload;

In the upload middleware, we define a key value. This key serves essentially as the image’s name in AWS, differentiating images in the list in the AWS Console. We are setting the key to the date at which the image is saved.

5. Set up route to handle image requests'/image-upload', function(req, res) {
   upload(req, res, (err) => {
      if (err) {
         return res.status(422).send({errors: [{title: 'File Upload Error', detail: err.message}] });

      return res.json({'imageUrl': req.file.location});

6. Set permissions to public

7. Send request in Postman to test it

8. Check the AWS S3 console to see if a new entry is there

The Date string that we set as the key value is in the Name field.

Uploading Images in Node with Multer

Multer is one of the most popular libraries for uploading files to a Node.js server. Multer is a Node.js middleware for handling multipart/form-data, which is primarily used for uploading files.

Install Multer package in your project

npm i multer

Create a form in your HTML file that will post to your server. Notice the enctype is set to multipart/form-data. Also, make sure to give your inputs names. That is how Multer finds them.

<form action="/" method="POST" enctype="multipart/form-data">
   <input type="text" name="name">
   <input type="file" name="image">
   <button type="submit">Submit</button>

Below is a very basic application of Multer. When our form makes a post request to the root, the Multer middleware (upload.single('image')) will give us access to the inputs in the request. The middleware takes in the name of the file input from your form. In our case, we called the input image. req.file holds the file uploaded to the form. req.body holds the text inputs.

When we defined our upload middleware, we set the destination in which we want to store our file uploads from Multer. In this case, files from our form will be stored in the uploads folder. If the folder doesn’t exist, it will be created automatically.

var express = require('express')
var multer  = require('multer')
var upload = multer({ dest: 'uploads/' })

var app = express()'/', upload.single('image'), function (req, res, next) {
  console.log(req.file, req.body);

Multer also allows us to customize the way that we handle file uploads.

The disk storage engine gives you full control on storing files to disk. There are two options available, destination and filename. They are both functions that determine where the file should be stored.

const storage = multer.diskStorage({
    destination: function (req, file, cb) {
       cb(null, './public/uploads');
    filename: function (req, file, cb) {
        cb(null, file.fieldname + '-' + + path.extname(file.originalname));

You append this storage property to your upload middleware

const upload = multer({
    storage: storage,

You can also create a filter function to define which types of files you want to accept and which types of files you don’t. For example, you can set your filter to only accept .png, .jpeg., and .jpg file types.

function checkFileType(file, cb) {
    // Allowed ext
    const filetypes = /jpeg|jpg|png/;
    // Check ext
    const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
    // Check mime
    const mimetype = filetypes.test(file.mimetype);

    if (mimetype && extname) {
        return cb(null, true);
    } else {
        cb('Error: Images Only');

Set this to the fileFilter property of the upload object:

const upload = multer({
    storage: storage,
    fileFilter: function (req, file, cb) {
        checkFileType(file, cb);

CSS Custom Properties (Variables)

CSS Custom Properties, or otherwise known as CSS Variables, allow us to handle dynamic values in our CSS. In the past, we had to use CSS preprocessors like Sass and Less to handle dynamic values or variables in our CSS. Now, CSS Custom Properties give us a native option that doesn’t have to be compiled and we can even access the variables in our JavaScript. You’ll get used to the weird syntax!

The process of defining and using variables is pretty similar no matter what part of the DOM you’re referencing. We will start with the root element, the body.

Define a variable by adding the two lines in front of its name (--). To reference the variable, use var(--style)

:root {
   --main-bg-color: #f4f4f4;

body {
   background-color: var(--main-bg-color);

Defining style variables for a div follows pretty much the same format. When you have a lot of variables, it can be helpful to separate the styles and the variables into two sections both referencing the same element.

.box {
   --box-bg-color: #fff;
   --box-main-color: #0e7;

.box {
   background-color: var(--box-bg-color);
   color: var(--box-main-color);

If you don’t have that many variables, you can define and reference them within the same block.

.grid {
   --gap: 20;
   grid-gap: var(--gap);

We can get access to the style variables we defined in CSS in our JavaScript. In this example, I’m referencing the box div, compiling all of the div‘s applied styles into a variable called boxStyles and getting access to the --box-main-color CSS variable from the boxStyles array.

const box = document.querySelector('.box');
const boxStyles = getComputedStyles(box);
const boxMainColor = boxStyles.getPropertyValue('--box-main-color')

const header = document.querySelector("#main-header");"--header-bg-color", boxMainColor);

I then set the header’s --header-bg-color CSS variable value to that of the boxMainColor that we extracted in the lines above.

CSS Grid Layout

CSS Grid allows us to create 2 dimension layouts and align items in columns and rows.

All browsers support grid layout.

Flexbox vs. Grid

CSS Grid vs Flexbox vs Bootstrap. When it comes to layout using ...
The primary difference between CSS Flexbox and Grids

First, I will create a div with the class grid. In order to use the grid layout, I will set the div’s display to grid in my CSS. Put some child elements within this container div with class grid in order to see its default behavior.

.grid {
   display: grid

After you set display: grid, you notice nothing really changes. We will have to define other CSS properties in order to see the effects of CSS grid.

.grid {
   display: grid
   grid-template-columns: 40% 60%;

This grid-template-columns property will actually cause things to change. If you have two child elements of the grid-display div, the first one will take up 40% of the available space and the second will take 50%. If you have more than two, the third, fourth, fifth, etc. will follow this same pattern, wrapping to the next line as necessary.

grid-template-columns: 40% 30% 30%;

You can add as many percentages as you like, as long as they add up to 100%. For each percentage, a new column will be placed onto the each line.

grid-column-gap: 1em;
grid-row-gap: 1em;

The grid-column-gap property adds spacing between each column (on the same line). The grid-row-gap property adds spacing between each row (between 2 lines). The grid-gap property will add the same amount of spacing to both rows and columns.

The recommended unit when using the grid-template-columns property is fractions.

This line, for example, separates the layout into 3 equal-sized columns– 1/3 each.

grid-template-columns: 1fr 1fr 1fr;

This line separates the layout into 1/4, 1/2, then 1/4 of the available width.

grid-template-columns: 1fr 2fr 1fr;

In order to make the syntax more succinct, you can write repeating template column layouts like this:

grid-template-columns: repeat(3, 1fr);

The above line does the same as 1fr 1fr 1fr. The below line repeats 1fr, 2fr, 1fr, 2fr, etc. four times.

grid-template-columns: repeat(3, 1fr, 2fr);

This line sets the height for every grid cell:

grid-auto-rows: 100px;

This line makes the default cell height 100px but expands a cell (and the other cells on its line) if the cell’s content requires more room:

grid-auto-rows: minmax(100px, auto);

The justify-items property allows you to define the location of grid cells within their defined space along the primary axis. It’s very similar to the justify property in Flexbox.

This is the default value of the justify-items property. It makes cells take up their entire horizontal space (in a horizontal grid).

justify-items: stretch

Some other property value options:

justify-items: start;  
justify-items: end;
justify-items: center;

The align-items property allows you to define the location of grid cells within their defined space along the cross axis. It’s very similar to the align property in Flexbox.

This is the default value of the align-items property. It makes cells take up their entire vertical space (in a horizontal grid).

align-items: stretch

Some other options for the property value:

justify-items: start;
justify-items: end;
justify-items: center;

You can set the justify and align properties of each individual grid element in order to only affect that element.

The grid-column and grid-row properties allow you to expand the amount of cell spaces that an individual cell takes up. These properties do this by using a property called lines.

Lines are the spaces between cells.

Grid Lines - MDN Web Docs Glossary: Definitions of Web-related ...

This line will make Cell 1 expand from row lines 1-3 (vertical expansion).

.cell1 {
   grid-row: 1/3;

React State Management with the Context API

Component-level state is the state within an individual component. It is only available to that component and only affects that component. We can use hooks such as useState to control component-level state.

But what if you want a piece of state to be available to multiple different components or all of your components? This is what we call application-level state.

Application-level state is the state that is available to the entire application. In order to implement this type of state, we need to implement more complex solutions.

One solution would be to “lift up” the state. This involved moving the piece of state to your App component, the root component which holds all of the other components. While this is a bit simpler to implement than other solutions, the problem with it is that you are giving the App component state that it doesn’t directly need and you will have to pass down the state to each component in a very long-winded way. This is called prop-drilling.

Instead, we can use the Context API as a more dynamic and versatile solution. Here’s an example of how it would be used:

Context File

import React, { useState, createContext } from 'react';

export const MyContext = createContext();

export const MyProvider = props => {
   const [property, setProperty] = useState('Initial state of property');

   return (
      <MyContext.Provider value={[property, setProperty]}>

App File

import React from 'react';
import { MyProvider } from './MyContext';

function App() {
   return (
            <MyComponent />
            Other Components...

Component File

import React, { useState, useContext } from 'react';
import { MyContext } from './MyContext';

const MyComponent = () => {
   const [property, setProperty] = useContext(MyContext);

   return (

export default MyComponent;

The downside to the Context API is every time we update the code in our Context, all the components that use the context have to re-render.

The benefits are that it’s more simple than Redux and doesn’t require any third-party libraries.