Skip to content
frappe-containerfile-generator logo

Frappe Containerfile Generator

frappe-containerfile-generator

Generate Containerfile for Frappe apps using the official frappe/erpnext images with Gunicorn. The recommended pattern copies app source into the bench layout and runs Gunicorn directly.

SKILL.md

Full skill instructions

Frappe Containerfile Generator

Generate Containerfiles for Frappe applications using the official docker.io/​frappe/​erpnext base images.

IMPORTANT: Frappe apps are NOT normal Python apps. They run inside the Frappe bench directory structure (/​home/​frappe/​frappe-bench) and require specific directory layout, user permissions, and the Gunicorn entry point frappe.app:application.

When to Use This Skill

Use this skill when:

  • Creating a Containerfile for any Frappe/​ERPNext custom app
  • Containerising a Frappe app for production deployment
  • A DevOps agent needs to produce a Containerfile for a Frappe-based tech stack

Recommended Containerfile Template

This is the standard pattern for all Frappe apps. Replace <app-name> with the actual app name (snake_case, matching the app's Python package name).

FROM docker.io/​frappe/​erpnext:version-15
USER root
WORKDIR /​home/​frappe/​frappe-bench

# Create asset directory and fix permissions
RUN mkdir -p sites/​assets/<app-name> && \
    chown -R frappe:frappe sites/​assets

USER frappe

WORKDIR /​home/​frappe/​frappe-bench

# Copy application files
COPY --chown=frappe:frappe . ./​apps/<app-name>/

# Install app, register in apps.txt, verify asset directory
RUN env/​bin/​python3 -m pip install -e ./​apps/<app-name> && \
    export BENCH_DEVELOPER=1 && \
    ls -1 ./​apps > sites/​apps.txt && \
    ls -l /​home/​frappe/​frappe-bench/​sites/​assets/<app-name> && \
    cat sites/​apps.txt

CMD [ \
    "/​home/​frappe/​frappe-bench/​env/​bin/​gunicorn", \
    "--chdir=/​home/​frappe/​frappe-bench/​sites", \
    "--bind=0.0.0.0:8000", \
    "--threads=4", \
    "--workers=2", \
    "--worker-class=gthread", \
    "--worker-tmp-dir=/​dev/​shm", \
    "--timeout=120", \
    "--preload", \
    "frappe.app:application" \
]

Concrete Example — app named invoicing

FROM docker.io/​frappe/​erpnext:version-15
USER root
WORKDIR /​home/​frappe/​frappe-bench

RUN mkdir -p sites/​assets/​invoicing && \
    chown -R frappe:frappe sites/​assets

USER frappe

WORKDIR /​home/​frappe/​frappe-bench

COPY --chown=frappe:frappe . ./​apps/​invoicing/

RUN env/​bin/​python3 -m pip install -e ./​apps/​invoicing && \
    export BENCH_DEVELOPER=1 && \
    ls -1 ./​apps > sites/​apps.txt && \
    ls -l /​home/​frappe/​frappe-bench/​sites/​assets/​invoicing && \
    cat sites/​apps.txt

CMD [ \
    "/​home/​frappe/​frappe-bench/​env/​bin/​gunicorn", \
    "--chdir=/​home/​frappe/​frappe-bench/​sites", \
    "--bind=0.0.0.0:8000", \
    "--threads=4", \
    "--workers=2", \
    "--worker-class=gthread", \
    "--worker-tmp-dir=/​dev/​shm", \
    "--timeout=120", \
    "--preload", \
    "frappe.app:application" \
]

App Name Substitution Rules (Mandatory)

  • Replace <app-name> everywhere with the real app slug (snake_case)
  • Keep the copy target and pip path in sync:
    • COPY --chown=frappe:frappe . ./​apps/<app-name>/
    • pip install -e ./​apps/<app-name>
  • Ensure asset path matches the same app slug:
    • sites/​assets/<app-name>

Example for qrcode:

RUN mkdir -p sites/​assets/​qrcode && \
    chown -R frappe:frappe sites/​assets

COPY --chown=frappe:frappe . ./​apps/​qrcode/

RUN env/​bin/​python3 -m pip install -e ./​apps/​qrcode && \
    export BENCH_DEVELOPER=1 && \
    ls -1 ./​apps > sites/​apps.txt && \
    ls -l /​home/​frappe/​frappe-bench/​sites/​assets/​qrcode && \
    cat sites/​apps.txt

Version Selection

Use the version that matches the target Frappe/​ERPNext deployment:

VersionBase image tagNotes
15version-15Default for new apps — stable, widely deployed
16version-16Latest, use when targeting v16 sites
14version-14Legacy, only for existing v14 deployments
FROM docker.io/​frappe/​erpnext:version-15
FROM docker.io/​frappe/​erpnext:version-16
FROM docker.io/​frappe/​erpnext:version-14

Multi-App Containerfile

When packaging multiple custom apps into one image:

FROM docker.io/​frappe/​erpnext:version-15
USER root
WORKDIR /​home/​frappe/​frappe-bench

RUN mkdir -p sites/​assets/​app_one sites/​assets/​app_two && \
    chown -R frappe:frappe sites/​assets

USER frappe

WORKDIR /​home/​frappe/​frappe-bench

COPY --chown=frappe:frappe ./​app_one ./​apps/​app_one/
COPY --chown=frappe:frappe ./​app_two ./​apps/​app_two/

RUN env/​bin/​python3 -m pip install -e ./​apps/​app_one && \
    env/​bin/​python3 -m pip install -e ./​apps/​app_two && \
    export BENCH_DEVELOPER=1 && \
    ls -1 ./​apps > sites/​apps.txt && \
    cat sites/​apps.txt

CMD [ \
    "/​home/​frappe/​frappe-bench/​env/​bin/​gunicorn", \
    "--chdir=/​home/​frappe/​frappe-bench/​sites", \
    "--bind=0.0.0.0:8000", \
    "--threads=4", \
    "--workers=2", \
    "--worker-class=gthread", \
    "--worker-tmp-dir=/​dev/​shm", \
    "--timeout=120", \
    "--preload", \
    "frappe.app:application" \
]

Critical Rules

  1. Base image: Always use docker.io/​frappe/​erpnext:version-{VER} — NEVER use generic UBI, Python, or Debian images
  2. Directory layout: Apps live under /​home/​frappe/​frappe-bench/​apps/<app-name>/
  3. Asset directory: Must create sites/​assets/<app-name> and chown to frappe:frappe
  4. User context: Start as root for mkdir/​chown, switch to frappe before COPY and RUN
  5. apps.txt: Must regenerate sites/​apps.txt after installing the app (ls -1 ./​apps > sites/​apps.txt)
  6. pip install: Use env/​bin/​python3 -m pip install -e (the bench virtualenv)
  7. Entry point: Gunicorn with frappe.app:application — NOT flask run, NOT bench start
  8. Port: Bind to 0.0.0.0:8000 (Frappe's standard port)
  9. COPY ownership: Always use --chown=frappe:frappe
  10. No EXPOSE needed: Port 8000 is implicit from the Gunicorn bind

Build and Run

podman build -t my-frappe-app .
podman run -p 8000:8000 my-frappe-app

Best Practices

  • Volume mounts for dev: don't bake app source into the image during development — use compose.yml with volume mounts instead
  • Layer optimization: combine RUN commands to reduce image layers
  • Permissions: always set --chown=frappe:frappe when copying files
  • Multi-arch: build for both amd64 and arm64 if distributing images
  • Version pinning: pin specific version tags, never use latest

Integration with frappe-new-app

When generating a new app, automatically include:

  1. Containerfile using the template above
  2. Place Containerfile in the app root directory
  3. Default to version-15 unless user specifies a version

More skills from vyogotech

frappe-data-migration-generator logo
vyogotech/frappe-apps-manager

frappe-data-migration-generator

Generate data migration scripts for Frappe. Use when migrating data from legacy systems, transforming data structures, or importing large datasets.

11 0
View
frappe-documentation-generator logo
vyogotech/frappe-apps-manager

frappe-documentation-generator

Generate API documentation, user guides, and technical documentation for Frappe apps. Use when documenting APIs, creating user guides, or generating OpenAPI specs.

11 0
View
Generate TDD Tests logo
vyogotech/frappe-apps-manager

Generate TDD Tests

Enforce the Iron Law of TDD for Frappe apps. Red-Green-Refactor cycle for DocTypes and Controllers.

11 0
View
frappe-controller logo
vyogotech/frappe-apps-manager

frappe-controller

Generate Frappe-style DocType controllers with lifecycle methods for microservices.

11 0
View
frappe-app-scaffold logo
vyogotech/frappe-apps-manager

frappe-app-scaffold

Canonical folder structure produced by `bench new-app` for modern Frappe (v14/v15+). Use this as the ground truth for any Frappe app file tree — includes pyproject.toml and module management.

11 0
View
frappe-api-handler logo
vyogotech/frappe-apps-manager

frappe-api-handler

Generate whitelisted API methods and REST endpoints for standard Frappe and microservices.

11 0
View
Validate Microservice Code logo
vyogotech/frappe-apps-manager

Validate Microservice Code

Validate code follows frappe-microservice-lib patterns, security best practices, and framework conventions.

11 0
View
frappe-tenant-query logo
vyogotech/frappe-apps-manager

frappe-tenant-query

Generate tenant-isolated database queries using TenantAwareDB to prevent cross-tenant access.

11 0
View
frappe-secure-endpoint logo
vyogotech/frappe-apps-manager

frappe-secure-endpoint

Generate secure, tenant-aware API endpoints with authentication and tenant isolation.

11 0
View
frappe-web-form-builder logo
vyogotech/frappe-apps-manager

frappe-web-form-builder

Generate Frappe Web Forms for public-facing forms. Use when creating customer portals, registration forms, surveys, or public data collection forms.

11 0
View
frappe-unit-test-generator logo
vyogotech/frappe-apps-manager

frappe-unit-test-generator

Generate comprehensive unit tests for Frappe DocTypes, controllers, and API methods. Use when creating test files, writing test cases, or setting up test infrastructure for Frappe/ERPNext applications.

11 0
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View