shrine

shrine.cr

!Logo Build Status GitHub release GitHub license

File attachment toolkit for Crystal applications. Inspired by Shrine for Ruby.

Installation

Add to your shard.yml:

dependencies:
  shrine:
    github: jetrockets/shrine.cr

Run shards install.

Core Concepts

Shrine separates file uploads into two parts:

  • Storage - where files are saved (disk, S3, SQLite)
  • Uploader - how files are processed and managed

Storage Backends

filesystem

Saves files to local disk. Best for development and small applications.

storage = Shrine::Storage::FileSystem.new(
  "uploads",                    # Base directory
  prefix: "images",             # Optional subdirectory
  clean: true                    # Remove empty folders
)

# Generated URLs: "/uploads/images/abc123.jpg"

S3

Amazon S3 or compatible services (DigitalOcean Spaces, MinIO). Best for production.

require "awscr-s3"

client = Awscr::S3::Client.new(
  region: "us-east-1",
  aws_access_key: ENV["AWS_KEY"],
  aws_secret_key: ENV["AWS_SECRET"]
)

storage = Shrine::Storage::S3.new(
  bucket: "my-bucket",
  client: client,
  public: true,                  # Make files publicly accessible
  prefix: "photos"               # Store in subfolder
)

# Generated URLs: "https://my-bucket.s3.amazonaws.com/photos/abc123.jpg"

SQLite

Stores files directly in SQLite database. Good for small apps and prototyping.

storage = Shrine::Storage::SQLite.new(
  "files.db",                    # Database file
  table: "uploads"                # Optional custom table name
)

# Generated URLs: "sqlite://files.db/uploads/abc123.jpg"

Memory

In-memory storage. Useful for testing.

storage = Shrine::Storage::Memory.new

# Data is lost when process ends

Plugins

DetermineMimeType

Detects actual MIME type from file content, not just extension.

require "shrine/plugins/determine_mime_type"

Shrine.plugin(Shrine::Plugins::DetermineMimeType)

# Now uploaded files have accurate mime_type metadata
uploaded.mime_type  # => "image/jpeg" (detected from content)

Analyzers:

  • File - Uses system file command (most accurate)
  • Mime - Uses file extension (fastest)
  • ContentType - Uses browser-provided header (least accurate)

StoreDimensions

Extracts image dimensions and adds them to metadata.

require "fastimage"
require "shrine/plugins/store_dimensions"

Shrine.plugin(Shrine::Plugins::StoreDimensions)

# After upload:
uploaded.width   # => 1920
uploaded.height  # => 1080
uploaded.dimensions  # => {1920, 1080}

Requires fastimage.cr.

Custom Uploaders

Create reusable uploaders with custom logic:

class ImageUploader < Shrine
  # Custom file naming
  def generate_location(io, metadata, **options)
    ext = File.extname(metadata["filename"].to_s)
    "images/#{Random::Secure.hex(8)}#{ext}"
  end
  
  # Automatic image processing
  def process(io, **options)
    # Generate thumbnail
    # Validate dimensions
    # Strip metadata
    io
  end
end

# Usage
uploader = ImageUploader.new
uploaded = uploader.upload(file, "store")

documentation


License

MIT

Repository

shrine

Owner
Statistic
  • 0
  • 0
  • 0
  • 0
  • 7
  • about 1 month ago
  • March 10, 2026
License

MIT License

Links
Synced at

Wed, 11 Mar 2026 03:03:17 GMT

Languages