AtomForge file management illustration

@atom-forge/attachment · Files

Files belong to your domain.

An avatar belongs to a user. A document belongs to a course. Attachment follows that ownership model, combining entity-local metadata with processing pipelines and storage providers instead of making every upload a new global database relation.

Entity ownership JSON metadata Image pipelines Storage providers

What it is

Metadata lives with the entity that owns it.

Attachment is a portable file-management system designed with Prisma integration in mind. Names, sizes, paths and MIME types are stored in an attachments JSON column on the owning entity, rather than requiring a standalone global File table.

Categories such as avatar and gallery define the rules for different kinds of files. A processing pipeline validates and transforms incoming uploads; a provider handles the resulting file storage.

Why choose Attachment?

A simpler ownership model

Entity-local metadata avoids a separate polymorphic relation for everyday attachments. Fetch the entity and its attachment metadata together.

Composable upload rules

Declare count limits, MIME checks and transformations in ordered pipelines. Add application-level size limits and authorization as part of your upload boundary.

Image processing where it belongs

The source describes sharp-backed WebP conversion and resizing before storage, plus on-demand thumbnails with a disk cache.

Separate storage from domain rules

A local provider supports filesystem storage. Other backends, such as S3, require an appropriate provider and deployment configuration; do not assume that storage is interchangeable without setup.

How it works

  1. Choose entities and categories

    Add the metadata column to the owning model, then define the categories it supports and their processing rules.

  2. Process and persist

    Run an authorized upload through its pipeline and persist the resulting metadata on the correct entity. Coordinate storage and database failures deliberately.

  3. Serve and maintain files

    Configure generated URLs, image variants and caching. Connect deletion and cleanup to your entity lifecycle rather than assuming a database delete removes stored bytes.

An honest fit check

Trade-offs, not fine print

Global reporting takes more work

An inventory of every file across the application is harder to query when metadata is distributed across JSON columns. If global search, auditing or independent file ownership is central, a relational file model may fit better.

JSON is an architectural commitment

Migrating to a normalized file table later requires extracting and transforming existing metadata. Check your database’s JSON support and query requirements first.

Runtime and storage constraints

Native image processing and a disk-backed thumbnail cache have deployment requirements. Plan persistent storage, cache limits and cleanup for your runtime.

In practice

One avatar, with an image pipeline

Adapted from the Attachment text. This shows category configuration, not a complete upload endpoint or a verified persistence recipe.

TypeScript · Illustrative · adapted from the source texts; package API not verified here
import {
  defineAttachments, count, mime, toWebP,
  imgstat, createLocalProvider,
} from '@atom-forge/attachment';

export const attachments = defineAttachments({
  user: defineAttachments.entity({
    avatar: [count(1), mime('image/*'), toWebP(80, 400, 400), imgstat()],
    gallery: [mime('image/*'), toWebP(80)],
  }),
}, {
  provider: createLocalProvider('./var/uploads'),
  servePrefix: '/file',
});

The database side of ownership

An illustrative Prisma model fragment. Schema migration, metadata updates and storage cleanup must be implemented for your application.

Prisma · Illustrative · adapted from the source texts; package API not verified here
model User {
  id          Int   @id @default(autoincrement())
  attachments Json?
}