node:net is the layer HTTP is built on, Stability 2 – Stable. A net.Server hands you a net.Socket per connection — an ordinary duplex stream, so Buffers and Streams applies unchanged — but not messages: TCP delivers bytes, so two socket.write calls can arrive as one data event and one write as three. Every protocol on TCP needs framing, here newlines.
import { createServer, connect } from 'node:net';
const server = createServer({ noDelay: true }, (socket) => {
socket.setEncoding('utf8'); let buf = ''; // TCP is a byte stream, not a message stream
socket.on('data', (chunk) => {
buf += chunk;
for (let i; (i = buf.indexOf('\n')) !== -1; buf = buf.slice(i + 1))
socket.write(buf.slice(0, i).toUpperCase() + '\n');
});
});
server.listen(7070, '127.0.0.1', async () => {
const client = connect(7070, '127.0.0.1').setEncoding('utf8');
client.end('hello from node\nbye for now\n');
for await (const chunk of client) process.stdout.write('<- ' + chunk);
server.close();
});Output
<- HELLO FROM NODE BYE FOR NOW
socket.setTimeout(ms) emits timeout after inactivity but closes nothing, so your handler must call socket.destroy(), and errors arrive as error events, never exceptions.