Back to Blog
    Programming Languages

    Node.js 22 LTS: Native TypeScript, WebSocket Client, Permission Model & More

    Mortex Solutions TeamFebruary 8, 202614 min read
    Node.js 22 LTS: Native TypeScript, WebSocket Client, Permission Model & More

    Node.js 22 is the latest LTS release, and it's packed with features that reduce the need for external tooling. Native TypeScript execution, built-in WebSocket, and the experimental permission model make Node.js more capable than ever.

    Node.js server development

    1. Native TypeScript Execution (--experimental-strip-types)

    Node.js can now run TypeScript files directly by stripping type annotations at runtime — no transpilation step needed for simple scripts.

    # Run TypeScript directly!
    node --experimental-strip-types app.ts
    
    # app.ts
    interface User {
      name: string;
      email: string;
    }
    
    function greet(user: User): string {
      return `Hello, ${user.name}!`;
    }
    
    console.log(greet({ name: "Mortex", email: "info@mortex.com" }));
    // Output: Hello, Mortex!

    2. Built-in WebSocket Client

    No more installing ws for basic WebSocket connections — Node.js 22 includes a standard-compliant WebSocket API.

    // No npm install needed!
    const ws = new WebSocket('wss://echo.websocket.org');
    
    ws.addEventListener('open', () => {
      console.log('Connected!');
      ws.send('Hello from Node.js 22');
    });
    
    ws.addEventListener('message', (event) => {
      console.log('Received:', event.data);
      ws.close();
    });
    
    ws.addEventListener('close', () => {
      console.log('Disconnected');
    });

    3. require(esm) — Use ES Modules in CommonJS

    One of the most requested features: you can now require() ES modules synchronously in CommonJS files.

    // lib.mjs (ES Module)
    export function add(a, b) {
      return a + b;
    }
    
    // app.cjs (CommonJS)
    const { add } = require('./lib.mjs'); // This now works!
    console.log(add(2, 3)); // 5

    4. Permission Model

    Restrict what your Node.js application can access — file system, network, child processes, and more.

    # Only allow reading from ./data and writing to ./output
    node --permission \
      --allow-fs-read=./data \
      --allow-fs-write=./output \
      --allow-net=api.example.com \
      app.js
    
    # In code, check permissions
    const { permission } = require('node:process');
    if (permission.has('fs.read', './secrets')) {
      console.log('Has access to secrets');
    } else {
      console.log('Access denied — running in restricted mode');
    }

    5. Built-in .env File Support

    # No more dotenv package!
    node --env-file=.env app.js
    
    # Multiple env files
    node --env-file=.env --env-file=.env.local app.js
    
    # .env
    DATABASE_URL=postgres://localhost:5432/mydb
    API_KEY=sk-abc123

    6. Native Test Runner (Stable)

    import { describe, it, before } from 'node:test';
    import assert from 'node:assert/strict';
    
    describe('UserService', () => {
      let service;
    
      before(() => {
        service = new UserService();
      });
    
      it('should create a user', async () => {
        const user = await service.create({
          name: 'Test',
          email: 'test@example.com'
        });
        assert.equal(user.name, 'Test');
        assert.ok(user.id);
      });
    
      it('should validate email format', () => {
        assert.throws(
          () => service.create({ name: 'Test', email: 'invalid' }),
          { message: /Invalid email/ }
        );
      });
    });
    
    // Run: node --test
    💡 Key Takeaway: Node.js 22 LTS reduces dependency on external packages significantly. Native TypeScript, WebSocket, .env, and test runner mean fewer npm install commands and simpler project setups.