From PHP to JavaScript with Node.js


I have been a PHP developer for more than 10 years and I recently moved to the JS full stack world. I was already familiar with JavaScript. I had my jQuery phase, then an Angular App and I finally started using React.

When I was a beginner in PHP, I embedded it in HTML files. My code was a mess. Therefore I started using frameworks to try organizing it: ZF1 and ZF2. With time passing, API-first approach left me with a server composed of a generated REST API and a few hundred lines of custom code.

As only a minor part of our projects was in PHP, a question arose; could we get rid of it? And if we could, what would be the cost and the benefits? In this article, I share my experience for those, like me, who want to move out of the PHP world and embrace the JS FullStack with solid grounds.

I will present you in this article mostly my journey on the server side from PHP to Node.js, and won’t talk about Webpack, React and other JS frontend technologies.

The stack evolution


The major changes of our Stack

Node.js is the main component of our new stack. It executes JavaScript programs at a great speed.

It does its job so well, that a lot of tools previously written in low-level languages have now their counterparts in JavaScript. Installing native programs was so tedious that we had to use Ansible to be able to deploy our stack. As our new tools of choice are now only dependent on Node.js, the only thing we have to install on the server ourselves is NVM (Node Version Manager): a tool dedicated to install Node.js.

How to install Node.js properly with NVM

Relying on the OS package manager or manually installing Node.js quickly led us to a lot of problems when we tried to switch versions. So we used NVM.

It’s very easy to setup:

wget -qO- | bash
nvm install node
nvm use v6.9.1

Once installed we were able to:

  • Install different Node.js versions on one system with one command
  • Switch seamlessly between those Node.js versions

Even better, NVM works on Linux, Mac and Windows thanks to nvm-windows.

JavaScript in 2017

When starting to learn JavaScript during my studies, it was seen as a garbage language, “sadly required” to make websites dynamic. So I never took the time to study it properly. I mostly learned about JavaScript from blog posts and stack-overflow answers. I regret it.


Take a break and RTFM!

I was not ready to start using modern JavaScript tools or framework. JavaScript in 2017 is a very different language, with modern features like:

  • Classes
  • Promises (now built-in in the language)
  • Destructuring & spread operator
  • Modules and module loaders
  • Maps / Sets and their weak versions
  • Async / Await

So it took time to go through a lot of material to learn Javascript the right way. The website gave me the best overview of what is programming in JavaScript nowadays.

From Composer to Yarn

Composer is a really nice tool but is slow. NPM has the same problem, so we picked Yarn instead. It’s a faster alternative to NPM.

On my last project, we had about a hundred dependencies. Among our team of 10 developers, we had at least 2 modifications of the node_modules folder per day.

(10 dev + 3 env) * 2 install/day * 60 days * 3 min/install = 78h

Indeed, two weeks were spent looking at loaders and reading Reddit. 3 minutes is long enough to add up to the cost of the project but too short to switch to another development task.

By bringing down the install time from 3 minutes to 1 minute with Yarn, we saved 46h of focus! That’s a good deal if you ask me.

Generating an API In JavaScript

The code will speak for itself. Here is a minimal example of an API Based on:

  • Express, a lightweight JavaScript equivalent to Zend Framework 2 / Symfony
  • Sequelize, an alternative to Doctrine
  • Epilogue, an alternative to Apigility
const Sequelize = require('sequelize'),
epilogue = require('epilogue'),
express = require('express'),
bodyParser = require('body-parser');

// Define your models with Sequelize
// This is equivalent to defining Doctrine entities
let database = new Sequelize('database', 'root', 'password');
let User = database.define('User', {
username: Sequelize.STRING

// Create an Express server
let app = express();
app.use(bodyParser.urlencoded({ extended: false }));

// Plug Epilogue into Express
app: app,
sequelize: database

// Configure a REST resource endpoint with Epilogue
let userResource = epilogue.resource({
model: User,
endpoints: ['/users', '/users/:id']

// And that's it, GET/POST and DELETE will be available for your user entity.
app.listen(() => {
console.log('Server started!');

With a few lines of code, we got a configurable and extendable REST API.

After having generated more than 50 API endpoints with Apigility, we were convinced that generating REST endpoints was possible AND efficient.

Epilogue generated our 10 endpoints without any problem. We were able to plug some custom code in the default workflow to handle complex rules, like user rights. What couldn’t be generated has been developed as simple Express RPC endpoints with the help of Sequelize.

It is true that Zend Framework 2 has way more features than Express. But Express has been elegant, lean and sufficient for all our needs. We didn’t miss anything.

I miss my types: Flow to the rescue

The ability to add input and return type hints to our PHP scripts, only when needed, was one of the features I loved the most in the language.

class UserService {
public function createUser(string $name, User $parent = null, $isAdmin) : User
$user = new User($name);
return $user

PHP has a powerful, yet flexible, type system

For many years I was thinking that there wasn’t a way to have the same support for types without committing to move to TypeScript.

I was wrong.

I discovered Flow, also known as Flow-type, and started to add types to my JavaScript files with ease.

Flow is an easy to install tool:

yarn add --save-dev flow-bin
node_modules/.bin/flow init

It’s an easy&nbsp;opt-in, we just had to add a one-liner at the top of the files we wanted to track:

/* @flow */ or // @flow

Then, the command “flow check” gives a full report based on the inferred types.

If your project uses a transpiler like Babel, new rules can be added to handle Flow types hints inside the JavaScript code like in PHP:


What if my server crashes? Monitor it with PM2

With PHP, a crashing script meant a request not served. With Node.js, if the server crashes, the website is down. So we had to manage our processes.

We switched from Supervisord&nbsp;to an awesome contender written in JavaScript:

❤&nbsp;PM2 (also know as Process Manager 2)&nbsp;❤

With a lot of hearts as it’s my favorite pick from this article

While having the benefit to be installed through Yarn, PM2 has other advantages. It supports all the Supervisord monitoring features and do more. It tracks the load and the memory of each processes and can be configured to reload them when their code change.


A single command, “pm2 list”, output a quick overview of the managed processes.

“pm2 monit” will give a detailed view of what is happening for each process in real time. Also, logging felt easier as we could, by default, use the native console.log()/.warn()/.error().


Visualize the outputs of your services and can track custom metrics.

Even better, while Supervisord scope is limited to the management of the processes, PM2 can also replace some deployment scripts with a simple configuration file:


A configuration file that allows to define and deploy your processes easily

PM2 is for me one of the biggest benefits of moving to a JavaScript full stack. Yet we can use it with any language, it’s just not as much integrated.

Configure your project with .env

Phing&nbsp;was used for three things in our projects:

  • Configuring the project
  • Scripting
  • Storing useful commands

In the JavaScript world, the configuration part can be handled by a .env&nbsp;file, with the great DotEnv&nbsp;library. It allows us to use environment variables to configure our app. It’s a good practice from The Twelve-Factor Appmethodology, a reference that we use daily.

The scripting part of Phing was not worth tooling anymore as all our scripts were, either linked to configurations of software outside of the PHP world, such as Supervisord, which we do not have any more or could be made as independent shell scripts in a few minutes.

At the end, the only role Phing would fulfill would have been storing commands and aliasing them. And this is wonderfully handled by Yarn (or NPM):

"name": "my project name",
"...": "...",
"scripts": {
"release": "standard-version",
"db-reset": "rm -rf data/main.db && sequelize db:migrate && sequelize db:seed:all",
"db-migrate": "sequelize db:migrate",
"dev": "pm2 delete all; pm2 startOrReload ecosystem.config.js && pm2 start react-scripts --name web -- start",
"start": "pm2 startOrReload ecosystem.config.js",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"flow": "flow"

So we could get rid of Phing entirely and call our commands like this:

yarn run db-migrate

Use good Open Source editors

When developing in PHP, I decided to use PhpStorm, a commercial IDE, as free ones felt slow and lacked plugins.

In JavaScript, there are more valid choices. Ours was to use VsCode, an editor made in JavaScript that is heavily supported by the community and Microsoft.


VsCode logo

So far, we’ve had a great experience using VsCode. It’s fast, has an awesome autocomplete engine and has a great community.

The ability to define which plugins are used on the project and to share their config is awesome. Anybody can, in one click, start coding right away with all the plugins pre-configured.

Get rid of manual linting with Prettier

In PHP we had something awesome. The PSRs. Those standards are really useful to define how the code should be written.

We configured our IDEs to follow PSR1&2. As there was no autocorrect feature, it was still up to everyone to enforce it. It wasn’t a great success.

Prettier&nbsp;comes to the rescue for JavaScript. Prettier is an opinionated code formatter that removes all original styling&nbsp;and ensures that all outputted code conforms to a consistent style every time you save your file.


Prettier in action. Illustration by Scott Sauber.

No more debates, no more training, no more useless time spent on merging style-only modifications.

Everyone on the team used it and LOVED it! Coding the strict minimum of style while we let Prettier take care of the details was awesome.




  • Our stack is easier to install and deploy
  • We don’t have to context switch between languages anymore
  • We are no longer relying on complex install scripts


  • It required a lot of research to establish a stack that matches our needs
  • We had to organize a lot of training to learn how to code in Javascript in 2017

We were able to quickly generate an API server like we used to do in PHP. I did not feel like leaving anything behind during the transition, all the tools we switched to were equivalent or better than before.


Share :

Leave a Reply

Your email address will not be published. Required fields are marked *

The reCAPTCHA verification period has expired. Please reload the page.