Display images stored in MySQL database using Node.js

I’m working on a Node.js project where I need to show images that are saved in a MySQL database. I created a table to store the image data like this:

CREATE TABLE photo_storage (
    photo_id INT AUTO_INCREMENT PRIMARY KEY,
    image_data LONGBLOB
);

I added an image to the database using this query:

INSERT INTO photo_storage (image_data) VALUES (LOAD_FILE('/home/user/photos/picture.jpg'));

In my Node.js application, I have this route that gets the data from MySQL:

app.get('/gallery', (request, response) => {
    connection.query('SELECT * FROM photo_storage', (error, results) => {
        if (error) {
            console.log(error);
        } else {
            response.render('gallery', {photos: results});
        }
    });
});

The problem is that when I run this code, I only see the photo IDs on my webpage instead of the actual images. How can I properly display these images that are stored as BLOB data in my MySQL table? I want them to show up as actual pictures on the screen.

You’re seeing photo IDs because the BLOB data isn’t being processed for display. Hit this same issue last year building a photo gallery. The problem is you’re missing proper content type handling and data conversion. When you pull BLOB data from MySQL through Node.js, it comes back as a Buffer object. Your template engine can’t render that as an image. You need to either convert it to base64 for inline display or create a separate image serving route with proper HTTP headers. Pro tip - double-check your LOAD_FILE query actually worked. File path permissions can cause silent failures and you’ll get NULL data. Check the byte length of your image_data field to verify. Also throw a content_type column in your table to store the original format (jpeg, png, etc). Makes serving way cleaner since you won’t have to guess the MIME type.

your blob data needs proper headers - browsers can’t figure out what to do with raw binary. add res.setHeader('Content-Type', 'image/jpeg') when you serve the image. also double-check that LOAD_FILE actually worked - mysql gets picky about file permissions and fails silently sometimes.

Setting up image serving from MySQL BLOB data manually is a pain. You’re stuck writing custom endpoints, handling content types, managing buffers, and debugging permission issues.

I automate this instead of coding it from scratch. Build a workflow that connects to your MySQL database, pulls BLOB data, converts it to proper image responses, and serves them through clean URLs.

The workflow handles the messy stuff - buffer conversion, MIME type detection, content headers, error handling. No separate image endpoints or base64 tricks needed.

Your gallery route stays simple. Just pass photo IDs to your template. The automation handles serving actual images when browsers request them.

I use this for all database image serving. Saves tons of maintenance headaches compared to custom Node.js image routes.

Latenode makes database to image workflows super straightforward: https://latenode.com

create a new endpoint that serves the blob data as an image. try app.get('/image/:id', (req, res) => { /* query db for the id */ res.set('Content-Type', 'image/jpeg'); res.send(results[0].image_data); }); then use <img src="/image/{{photo_id}}"> in your template.

Hit this same problem six months ago rebuilding our product catalog. MySQL returns BLOB data as Buffer objects in Node.js, so template engines can’t display them as images. I went with a hybrid solution - kept the separate image endpoint like jess_brown suggested but added proper error handling and MIME detection. Built a simple utility that reads the first few bytes of each BLOB to identify the actual format instead of assuming jpeg. Saves you from broken images when formats are mixed. Also found out LOAD_FILE is picky - MySQL needs FILE privileges and the exact file path must be accessible to the server process. I’d add a verification step after insertion to make sure the BLOB actually contains image data and isn’t just NULL.

Convert your BLOB data to base64 and embed it straight into your HTML template. In your route handler, modify the results before sending them to the view: results.forEach(photo => { photo.image_base64 = photo.image_data.toString('base64'); }); Then use <img src="data:image/jpeg;base64,{{image_base64}}"> in your template. Works great for smaller images, but heads up - it’ll bloat your HTML size big time. For larger images, I’d go with jess_brown’s separate endpoint approach or just store file paths instead of the raw image data.

BLOB data and manual conversion is a total mess. Been there, done that - it’s a maintenance nightmare every time.

You need automation that handles the whole image processing pipeline. Build a workflow that grabs your database BLOB data and converts it to proper image responses automatically. No custom endpoints or base64 conversion code.

The workflow monitors your database, pulls BLOB data when needed, sets content headers, and serves actual images. Skip the forEach loops and custom route handlers.

I do this for all my image serving. It handles content type detection and caching automatically. Way cleaner than embedding base64 in HTML or writing separate image endpoints.

Keep your templates simple with regular img tags. The automation converts BLOB to proper image responses behind the scenes.

Check out Latenode for automated image processing workflows: https://latenode.com