cd /news/machine-learning/how-i-built-an-in-memory-explicit-co… · home topics machine-learning article
[ARTICLE · art-112256] src=dev.to ↗ pub= topic=machine-learning verified=true sentiment=· neutral

How I built an in-memory explicit content filter in Node.js (200ms latency, zero images saved)

A developer built an in-memory explicit content filter for Node.js that classifies images without ever writing them to disk, achieving roughly 200ms latency. The solution uses multer's memoryStorage and the nsfwjs library with TensorFlow.js to keep images only in RAM, addressing privacy and liability concerns. The developer also launched an API called Tabu based on this logic.

read3 min views4 publishedAug 26, 2026

If you allow user-generated content in your app, you eventually run into a massive liability problem. Users will upload NSFW images.

I ran into this exact problem when Apple rejected my previous app under Guideline 1.2 (User Generated Content). I needed a filter, but the standard way most tutorials teach you to handle this is flawed.

Usually, the process goes like this:

The problem? The explicit image actually hits your hard drive before you know it is explicit. If the background job fails or is delayed, you are temporarily hosting illegal or policy-violating content on your servers.

To solve this, I built a single Node.js endpoint that runs the entire classification in memory.

Instead of saving the file to disk, the server receives the image as a buffer, passes that buffer directly to a lightweight machine learning model, gets the score, and immediately destroys the buffer. The image never touches a hard drive.

Here is the core logic using the open-source nsfwjs

library and TensorFlow.js:

const express = require('express');
const multer = require('multer');
const tf = require('@tensorflow/tfjs-node');
const nsfwjs = require('nsfwjs');

const app = express();
// Keep the file in memory, do not write to disk
const upload = multer({ storage: multer.memoryStorage() });

let _model;
const loadModel = async () => {
    _model = await nsfwjs.load();
};

app.post('/moderate', upload.single('image'), async (req, res) => {
    if (!req.file) {
        return res.status(400).json({ error: 'No image provided' });
    }

    try {
        // 1. Decode the image buffer directly from memory
        const imageTensor = tf.node.decodeImage(req.file.buffer, 3);

        // 2. Pass the tensor to the model
        const predictions = await _model.classify(imageTensor);

        // 3. Destroy the tensor to free memory immediately
        imageTensor.dispose();

        // 4. Return the scores
        return res.json(predictions);

    } catch (error) {
        return res.status(500).json({ error: 'Processing failed' });
    }
});

loadModel().then(() => app.listen(3000));

1. Total Privacy. Because we use multer.memoryStorage()

, the image exists only in RAM for the fraction of a second it takes to run the classification. Once the request ends, Node.js garbage collects the buffer. You can legally guarantee your users that you are not storing their private photos.

2. Speed. Bypassing the file system completely keeps the classification extremely fast. In my testing, it drops to roughly 200ms per image on a standard VPS.

3. Simplicity. It is a synchronous API call. You can run this check before your database transaction even commits, keeping your backend architecture clean.

If you want to run this yourself, the code snippet above is pretty much all you need to get started. Just watch your server memory, as TensorFlow tensors will cause a memory leak if you forget to call .dispose()

.

If you don't want to bother hosting the ML models or managing the RAM yourself, I actually wrapped this exact logic into an API called Tabu that I launched recently. It has a free tier that is plenty for testing, so feel free to use it if you want to skip the server setup.

Let me know how you guys handle image moderation in your own side projects!

── more in #machine-learning 4 stories · sorted by recency
── more on @node.js 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/how-i-built-an-in-me…] indexed:0 read:3min 2026-08-26 ·