Skip to main content
Cloudinary is used in PC Fix for storing and delivering product images and receipt uploads through a global CDN. This integration provides automatic image optimization, format conversion, and secure storage.

Overview

PC Fix uses Cloudinary for:
  • Product Images: Automatically converted to WebP format for optimal performance
  • Receipt Uploads: Supports images and PDF files for payment verification
  • CDN Delivery: Fast global content delivery through Cloudinary’s CDN

Configuration

1

Create a Cloudinary Account

Sign up for a free account at cloudinary.com. The free tier includes 25GB storage and 25GB bandwidth per month.
2

Get Your API Credentials

Navigate to your Cloudinary Dashboard and copy:
  • Cloud Name
  • API Key
  • API Secret
3

Set Environment Variables

Add these variables to your .env file in the packages/api directory:
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret
Never commit your .env file to version control. Cloudinary credentials should remain secret.

Implementation

Upload Middleware

Cloudinary is configured in the upload middleware at packages/api/src/shared/middlewares/uploadMiddleware.ts:
import multer from 'multer';
import { v2 as cloudinary } from 'cloudinary';
import { CloudinaryStorage } from 'multer-storage-cloudinary';

// Configure Cloudinary
cloudinary.config({
  cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
  api_key: process.env.CLOUDINARY_API_KEY,
  api_secret: process.env.CLOUDINARY_API_SECRET,
});

// Product image storage
const productStorage = new CloudinaryStorage({
  cloudinary: cloudinary,
  params: async (req: any, file: any) => {
    return {
      folder: 'pcfix-products',
      format: 'webp',
      public_id: `foto-${Date.now()}-${Math.round(Math.random() * 1e9)}`,
    };
  },
});

// Receipt storage
const receiptStorage = new CloudinaryStorage({
  cloudinary: cloudinary,
  params: async (req: any, file: any) => {
    return {
      folder: 'pcfix-receipts',
      resource_type: 'auto',
      public_id: `comprobante-${Date.now()}-${Math.round(Math.random() * 1e9)}`,
    };
  },
});

Upload Instances

Two multer instances are exported for different use cases:
export const upload = multer({
  storage: productStorage,
  limits: { fileSize: 5 * 1024 * 1024 }, // 5MB limit
  fileFilter: imageFilter, // jpg, jpeg, png, webp, gif
});

Usage Examples

Uploading Product Images

Use the upload middleware in your routes:
import { upload } from '@/shared/middlewares/uploadMiddleware';

// Single image upload
router.post('/products', 
  authMiddleware,
  adminMiddleware,
  upload.single('foto'),
  createProduct
);

// Access uploaded file URL
const imageUrl = req.file?.path; // Cloudinary URL

Uploading Receipts

Use the uploadReceipt middleware for payment verification:
import { uploadReceipt } from '@/shared/middlewares/uploadMiddleware';

router.post('/sales/:id/receipt',
  authMiddleware,
  uploadReceipt.single('comprobante'),
  uploadReceipt
);

const receiptUrl = req.file?.path; // Cloudinary URL

Frontend Configuration

To enable Cloudinary URLs in Astro, add the domain to your astro.config.mjs:
astro.config.mjs
export default defineConfig({
  image: {
    domains: [
      'res.cloudinary.com' // Cloudinary CDN
    ],
    remotePatterns: [{ protocol: "https" }],
  },
});
Add preconnect to improve loading performance in your layout:
Layout.astro
<link rel="preconnect" href="https://res.cloudinary.com" crossorigin />

Folder Structure

Cloudinary organizes uploads into folders:
  • pcfix-products/ - Product images (auto-converted to WebP)
  • pcfix-receipts/ - Payment receipts (images and PDFs)

File Constraints

Product Images

  • Max Size: 5MB
  • Formats: JPEG, PNG, WebP, GIF
  • Output: Auto-converted to WebP

Receipts

  • Max Size: 10MB
  • Formats: JPEG, PNG, WebP, GIF, PDF
  • Output: Original format preserved

Benefits

Product images are automatically converted to WebP format, reducing file size by up to 30% while maintaining quality.
Images are delivered through Cloudinary’s global CDN, ensuring fast load times for users worldwide.
Files are automatically renamed using timestamps and random numbers to prevent collisions.
No need to manage file storage on your server. Cloudinary handles all storage and scaling automatically.

Troubleshooting

Check that your CLOUDINARY_API_KEY and CLOUDINARY_API_SECRET are correct in your .env file.
Ensure res.cloudinary.com is added to the domains array in astro.config.mjs.
Product images are limited to 5MB, receipts to 10MB. Compress images before uploading or adjust the limits in uploadMiddleware.ts.

Security Considerations

  • API credentials are validated server-side only
  • File type restrictions prevent unauthorized file uploads
  • Unique file names prevent directory traversal attacks
  • CORS configuration restricts access to authorized domains

Build docs developers (and LLMs) love