# Writing Node.js in 2025? These New Features & Practices Are Non-Negotiable

If you’re still writing Node.js apps the “old way” (CommonJS modules, dotenv, external test libs, etc), it’s time to upgrade. Modern versions of Node.js offer several built-in capabilities that reduce dependencies, simplify workflow, and improve performance. In this blog I’ll walk you through **8 key built-in features** you should adopt right now with short code samples, clear guidance and caveats so you can migrate confidently.

## 1\. Embrace the latest import syntax (ESM)

Stop using the old `require()`/CommonJS style if you can. Node.js fully supports ECMAScript modules (ESM) and it’s time to use them. [Node.js+2W3Schools+2](https://nodejs.org/api/esm.html?utm_source=chatgpt.com)

**Old (outdated):**

```bash
const express = require('express');
module.exports = someFunction;
```

**Recommended (ESM):**

```bash
import express from 'express';
export default someFunction;
```

Set `"type": "module"` in your `package.json`, or use `.mjs` extensions, and you’re good. Going ESM from day one is cleaner, more aligned with modern JS, and avoids interoperability headaches.

---

## 2\. Use `process.env` via run command instead of dotenv (in many cases)

I know many of us used `dotenv.config()` at the top of our apps. That still works, but recent Node.js updates allow you to pass environment files at runtime without requiring `dotenv`. That’s one less dependency to manage.

**Old pattern:**

```bash
import dotenv from 'dotenv';
dotenv.config();

console.log(process.env.MY_SECRET);
```

**Recommended runtime command:**

```bash
node --env-file=.env app.js
```

This way you can skip or minimise `dotenv` usage (especially in production) and rely more on the runtime’s built-in env file support. It keeps things simple and reduces third-party reliance.

---

## 3\. Built-in test runner in Node.js

Remember when you had to install and configure Jest, Mocha or Vite for testing? That’s changing. Node.js now ships with a built-in test runner. [Node.js+2LogRocket Blog+2](https://nodejs.org/api/test.html?utm_source=chatgpt.com)

**Sample code:**

```bash
// math.test.mjs
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { add } from './math.js';

test('adds two numbers', () => {
  assert.strictEqual(add(2, 3), 5);
});
```

Then simply run:

```bash
node --test
```

Benefits: zero additional dependency, minimal config, and smoother dev experience. Of course, if you need advanced features, you may still pick Jest/Mocha, but for many use-cases this built-in runner suffices.

---

## 4\. Native SQLite support (yes, really)

One of the big surprises: Node.js v22.5.0 introduced a built-in experimental module for SQLite: `node:sqlite`. [Better Stack+2LogRocket Blog+2](https://betterstack.com/community/guides/scaling-nodejs/nodejs-sqlite/?utm_source=chatgpt.com)

**Note (call-out):** Use the special prefix `node:packageName` when importing built-in modules. This ensures you’re referencing a built-in library, not a third-party with the same name (security + clarity win).

**Example usage:**

```bash
import { DatabaseSync } from 'node:sqlite';

const db = new DatabaseSync('example.db');

db.run('CREATE TABLE users(id INTEGER PRIMARY KEY, name TEXT)');
db.run('INSERT INTO users(name) VALUES (?)', 'Alice');

const row = db.get('SELECT * FROM users WHERE name = ?', 'Alice');
console.log(row);
```

⚠️ Keep in mind: still marked experimental, fewer features than popular third-party libs (like concurrency, async API). Use with caution for production. [LogRocket Blog](https://blog.logrocket.com/using-built-in-sqlite-module-node-js/?utm_source=chatgpt.com)

---

## 5\. “Type-skipper” support for TypeScript files

If you’re doing TypeScript, there’s good news: recent Node.js versions let you run `.ts` files directly (for the parts that just use types). [Node.js+1](https://nodejs.org/api/typescript.html?utm_source=chatgpt.com)

**Example:**

```bash
// app.ts
const greet = (name: string): string => {
  return `Hello, ${name}`;
};

console.log(greet('World'));
```

You can run:

```bash
node app.ts
```

**Important call-out:** This only supports *type stripping* (erasable TypeScript syntax). Full TS features (enums, namespaces, fancy transforms) still need compile/transpile. Use this feature vigilantly, understand its limitations, and stay tuned for future updates.

---

## 6\. Replace nodemon with Node’s built-in `--watch` flag

You probably used nodemon for auto-restarting on file changes. Now, Node.js offers a built-in flag `--watch`. Make your life simpler.

**Example:**

```bash
node --watch server.js
```

On changes, Node will auto-reload. Fewer dependencies and tools to maintain.

---

## 7\. Built-in `fetch` (no more axios or node-fetch)

Modern Node.js versions include the Fetch API natively—just like in browsers. That means you don’t always have to import axios or `node-fetch`.

**Example:**

```bash
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
```

Saves you package installations, simplifies your stack.

---

## 8\. Super-fast dev script with `node --run dev` (yes, no npm needed)

This is one of the cleanest improvements in modern Node.js.  
You **don’t need** slow `npm run dev` anymore because npm adds extra overhead (pre-scripts, post-scripts, lifecycle steps, etc).

Now Node.js gives you a **native script runner** using:

```
node --run dev
```

So you define your scripts in `package.json` like this:

```
{
  "scripts": {
    "dev": "node --watch server.js"
  }
}
```

And instead of:

```bash
npm run dev
```

You can directly run:

```bash
node --run dev
```

This is **lightning fast**, no npm layer, no extra processing.  
Just pure Node executing your script instantly , perfect for local development.

---

### Final Thoughts

If you’re working with Node.js right now (especially v22+), start shifting to these built-in features. They genuinely cut down your dependency list, reduce config headaches, and make your whole dev workflow faster and cleaner. This is the direction Node.js is moving toward, so adopting early gives you an edge.

But remember not everything is 100% production-ready. Features like native SQLite and TypeScript type-skipping are still evolving. Use them smartly, test properly, and make sure your project actually benefits from the switch.

Node.js is changing fast, and these built-in upgrades are going to become the new “default way” of writing backend apps. So stay updated, experiment, and keep your stack modern.

More improvements are coming , stay tuned.
