Cloudron makes it easy to run web apps like WordPress, Nextcloud, GitLab on your server. Find out more or install now.


Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Bookmarks
  • Search
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo

Cloudron Forum

Apps - Status | Demo | Docs | Install
  1. Cloudron Forum
  2. App Wishlist
  3. TinaCMS on Cloudron - Git-backed headless content management system (CMS)

TinaCMS on Cloudron - Git-backed headless content management system (CMS)

Scheduled Pinned Locked Moved App Wishlist
tinacmsforestrycms
6 Posts 2 Posters 460 Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • L Offline
    L Offline
    LoudLemur
    wrote on last edited by
    #1

    TinaCMS used to be Forestry. It is a Content Management System which is platform agnostic and offers basic or visual editing and synchronization with Git.

    Frameworks-Agnostic
    Tina supports all frameworks and static site generators.

    Git-Sync
    Similar to Forestry, Tina commits content changes to your repository.

    Basic or Visual Editing
    Tina's basic editing mode is similar to editing content with Forestry. Tina also supports visual editing which shows a live preview of your site as you edit content.

    Multi-Branch
    Create new branches and switch between them right from the Tina UI.

    Open-Source and Extensible
    Tina is very customizable and extensible due to it's open-source nature.

    Local Development
    TinaCMS can be run locally alongside your site. You can make changes to your content models and fields, and see the results immediately.

    Licence: Apache v2.0
    https://tina.io/docs/
    https://github.com/tinacms/tinacms
    Demo: https://app.tina.io/quickstart
    Docker: Couldn't see one

    There is a very nice set of comparisons between TinaCMS and others at the bottom of the main page.

    brave_ki9wUCuccS.png

    1 Reply Last reply
    2
    • L Offline
      L Offline
      LoudLemur
      wrote last edited by
      #2

      If your users want to edit their astro / svelte websites, this is a sweet tool. There have been updates since this was first requested. Lets support TinaCMS on Cloudron!

      Since the self-hosting auth went fully open-source ~late 2023, main changes are maintenance-focused.
      Categorized Improvements

      CategoryDetailsCompatibility- Next.js 15 & React 19 support (v17.0.2)

      • TinaCMS core sync to 3.5.1
      • ESM examples updated
      • Schema tools bumpsSecurity- Next.js patched for DoS CVEs (2025-55184, 2025-67779) in v15.0.1Maintenance- Ongoing dependency alignment
      • Refined auth providers (DefaultAuthJSProvider)
      1 Reply Last reply
      2
      • L Offline
        L Offline
        LoudLemur
        wrote last edited by
        #3

        TinaCMS Self-Hosted on Cloudron: Lessons Learned & Blockers
        TL;DR: After ~20 hours of work across multiple sessions, we were unable to get TinaCMS self-hosted edition fully working as a Cloudron custom app. The admin UI loads and authentication works, but the GraphQL API fails to serve schema data. Below are the key findings for anyone attempting this — either as a custom app or as a potential Cloudron package.

        What We Built
        A Docker image based on cloudron/base:4.2.0 running TinaCMS's self-hosted Next.js starter with:

        MongoDB adapter (mongodb-level) instead of the default SQLite (Cloudron provides MongoDB as an addon)
        NextAuth credential-based login using tinacms-authjs
        GitHub as the Git provider for content storage
        Pre-built admin UI baked into the Docker image at /public/admin/index.html

        Architecture:
        Browser → Cloudron reverse proxy → :8000 → Next.js (pages router)
        ↓
        /api/tina/gql (GraphQL)
        ↓
        TinaCMS backend
        ↙ ↘
        MongoDB GitHub API
        (schema cache) (content CRUD)

        What Works

        Health check endpoint (/api/health)
        Admin UI loads at /admin/index.html
        NextAuth login/logout (credentials provider via TinaAuthJSOptions)
        API route responds with JSON ({"error":"Unauthorized"} for unauthenticated requests — correct behaviour)
        Content repo on GitHub receives pushes
        Docker image builds and deploys cleanly

        What Doesn't Work
        The GraphQL endpoint (/api/tina/gql) returns "Unable to complete request" for all authenticated queries. The schema is never indexed into MongoDB.

        Showstoppers Encountered (In Order)

        1. Image Upload Size (413 Errors)
          Problem: Cloudron's built-in upload limit blocks large Docker image pushes via the web UI.
          Solution: Use podman (or Docker) to push images to Docker Hub, then cloudron update --image.
        2. MongoDB Adapter Swap
          Problem: TinaCMS defaults to SQLite (level). Cloudron provides MongoDB but not SQLite persistence across restarts.
          Solution: Replace with mongodb-level package. Use CLOUDRON_MONGODB_URL and CLOUDRON_MONGODB_DATABASE environment variables.
        3. Build-Time vs Runtime Split
          Problem: tinacms build requires a live MongoDB connection for schema indexing. Docker builds don't have database access.
          Solution: Split into two phases:

        Docker build: pnpm run build:next only (compiles Next.js)
        Runtime: Schema indexing must happen inside the running container

        1. Health Check Configuration
          Problem: TinaCMS has no built-in health endpoint. Cloudron requires one.
          Solution: Create /pages/api/health.ts returning 200 OK. Set healthCheckPath: "/api/health" in CloudronManifest.json.
        2. ESM Module Compatibility (The Big One)
          Problem: Multiple packages in TinaCMS's dependency tree are ESM-only (mongodb-level → abstract-level, nanoid@5, react-dnd-html5-backend). Next.js pages router API routes use CommonJS. This causes ERR_REQUIRE_ESM at runtime.
          Attempted fixes:

        transpilePackages in next.config.js — doesn't help because TinaCMS bundles database separately via esbuild
        Pre-bundling mongodb-level with esbuild into a single CJS file — fixes that one package but others appear
        Downgrading nanoid to v3 via pnpm overrides — fixes nanoid but react-dnd-html5-backend takes its place
        What finally worked: Upgrading Node.js from 18 (Cloudron base) to 22, which supports require() of ESM modules natively

        Key insight: The Cloudron base image (cloudron/base:4.2.0) ships Node 18 with a hardcoded PATH. To use Node 22:
        dockerfileRUN npm install -g n && n 22 && rm -rf /usr/local/node-18.18.0
        ENV PATH="/usr/local/bin:/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin"
        6. NextAuth Route Missing
        Problem: The TinaCMS self-hosted starter's [...routes].ts uses AuthJsBackendAuthProvider with TinaAuthJSOptions, but there was no corresponding /api/auth/[...nextauth].ts route to handle login.
        Solution: Create the NextAuth catch-all route using the same TinaAuthJSOptions config.
        7. Schema Indexing
        Problem: tinacms build --skip-cloud-checks (without --skip-indexing) fails inside the container with "The service was stopped / Unable to build". The schema is never populated in MongoDB, so all GraphQL queries fail.
        Status: Unresolved. This is where we stopped.
        8. Memory Requirements
        Cloudron's default memory allocation (256MB or 512MB) is insufficient. The app needs at least 2–4GB during schema indexing. OOM kills manifest as silent 500 errors.

        Key Files
        FilePurposeCloudronManifest.jsonhealthCheckPath, runtimeDirs, memory limit, addonsstart.shBridges Cloudron env vars (CLOUDRON_MONGODB_URL → MONGODB_URI), generates NEXTAUTH_SECRET on first runDockerfileNode 22 via n, two-stage build, prod-only depstina/database.tsMongoDB adapter configpages/api/tina/[...routes].tsGraphQL endpoint with AuthJsBackendAuthProviderpages/api/auth/[...nextauth].tsNextAuth login handlerpages/api/health.tsCloudron health check

        Advice for Custom App Installers

        Start with Node 22. Don't waste time on ESM workarounds.
        Allocate 4GB RAM minimum for the app during setup.
        Use Docker Hub (or GHCR) as an intermediary for image pushes — never the Cloudron web upload.
        Test locally with podman run before every deploy. The Cloudron update cycle is 5–10 minutes.
        The schema indexing problem is the critical unsolved piece. TinaCMS expects tinacms build to run with database access, but this is difficult in Cloudron's immutable container model.

        Advice for Cloudron Packagers

        TinaCMS is not packaging-friendly. It conflates build-time code generation with runtime schema indexing. There's no clean separation.
        The MongoDB adapter (mongodb-level) works but adds ESM complexity. Consider whether SQLite with persistent storage (/app/data) might be simpler.
        tinacms build needs a running database. Either:

        Run it as a post-start hook before Next.js starts
        Or find a way to pre-generate the schema and load it at startup

        Auth is tightly coupled. tinacms-authjs expects both the GraphQL route and the NextAuth route to use the same TinaAuthJSOptions factory — which itself requires the database client.
        Memory: Budget 1GB steady-state, 2–4GB for indexing operations.

        Environment Reference
        Cloudron base: 4.2.0
        Node.js: 22.22.0 (via n)
        TinaCMS: 2.10.1
        Next.js: 14.2.35
        next-auth: 4.24.13
        tinacms-authjs: 5.0.9
        mongodb-level: (bundled via esbuild)
        pnpm: 10.30.x

        Posted in the hope of saving someone else 20 hours. If you've successfully packaged TinaCMS for Cloudron, please share your approach!

        timconsidineT 1 Reply Last reply
        1
        • L LoudLemur

          TinaCMS Self-Hosted on Cloudron: Lessons Learned & Blockers
          TL;DR: After ~20 hours of work across multiple sessions, we were unable to get TinaCMS self-hosted edition fully working as a Cloudron custom app. The admin UI loads and authentication works, but the GraphQL API fails to serve schema data. Below are the key findings for anyone attempting this — either as a custom app or as a potential Cloudron package.

          What We Built
          A Docker image based on cloudron/base:4.2.0 running TinaCMS's self-hosted Next.js starter with:

          MongoDB adapter (mongodb-level) instead of the default SQLite (Cloudron provides MongoDB as an addon)
          NextAuth credential-based login using tinacms-authjs
          GitHub as the Git provider for content storage
          Pre-built admin UI baked into the Docker image at /public/admin/index.html

          Architecture:
          Browser → Cloudron reverse proxy → :8000 → Next.js (pages router)
          ↓
          /api/tina/gql (GraphQL)
          ↓
          TinaCMS backend
          ↙ ↘
          MongoDB GitHub API
          (schema cache) (content CRUD)

          What Works

          Health check endpoint (/api/health)
          Admin UI loads at /admin/index.html
          NextAuth login/logout (credentials provider via TinaAuthJSOptions)
          API route responds with JSON ({"error":"Unauthorized"} for unauthenticated requests — correct behaviour)
          Content repo on GitHub receives pushes
          Docker image builds and deploys cleanly

          What Doesn't Work
          The GraphQL endpoint (/api/tina/gql) returns "Unable to complete request" for all authenticated queries. The schema is never indexed into MongoDB.

          Showstoppers Encountered (In Order)

          1. Image Upload Size (413 Errors)
            Problem: Cloudron's built-in upload limit blocks large Docker image pushes via the web UI.
            Solution: Use podman (or Docker) to push images to Docker Hub, then cloudron update --image.
          2. MongoDB Adapter Swap
            Problem: TinaCMS defaults to SQLite (level). Cloudron provides MongoDB but not SQLite persistence across restarts.
            Solution: Replace with mongodb-level package. Use CLOUDRON_MONGODB_URL and CLOUDRON_MONGODB_DATABASE environment variables.
          3. Build-Time vs Runtime Split
            Problem: tinacms build requires a live MongoDB connection for schema indexing. Docker builds don't have database access.
            Solution: Split into two phases:

          Docker build: pnpm run build:next only (compiles Next.js)
          Runtime: Schema indexing must happen inside the running container

          1. Health Check Configuration
            Problem: TinaCMS has no built-in health endpoint. Cloudron requires one.
            Solution: Create /pages/api/health.ts returning 200 OK. Set healthCheckPath: "/api/health" in CloudronManifest.json.
          2. ESM Module Compatibility (The Big One)
            Problem: Multiple packages in TinaCMS's dependency tree are ESM-only (mongodb-level → abstract-level, nanoid@5, react-dnd-html5-backend). Next.js pages router API routes use CommonJS. This causes ERR_REQUIRE_ESM at runtime.
            Attempted fixes:

          transpilePackages in next.config.js — doesn't help because TinaCMS bundles database separately via esbuild
          Pre-bundling mongodb-level with esbuild into a single CJS file — fixes that one package but others appear
          Downgrading nanoid to v3 via pnpm overrides — fixes nanoid but react-dnd-html5-backend takes its place
          What finally worked: Upgrading Node.js from 18 (Cloudron base) to 22, which supports require() of ESM modules natively

          Key insight: The Cloudron base image (cloudron/base:4.2.0) ships Node 18 with a hardcoded PATH. To use Node 22:
          dockerfileRUN npm install -g n && n 22 && rm -rf /usr/local/node-18.18.0
          ENV PATH="/usr/local/bin:/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin"
          6. NextAuth Route Missing
          Problem: The TinaCMS self-hosted starter's [...routes].ts uses AuthJsBackendAuthProvider with TinaAuthJSOptions, but there was no corresponding /api/auth/[...nextauth].ts route to handle login.
          Solution: Create the NextAuth catch-all route using the same TinaAuthJSOptions config.
          7. Schema Indexing
          Problem: tinacms build --skip-cloud-checks (without --skip-indexing) fails inside the container with "The service was stopped / Unable to build". The schema is never populated in MongoDB, so all GraphQL queries fail.
          Status: Unresolved. This is where we stopped.
          8. Memory Requirements
          Cloudron's default memory allocation (256MB or 512MB) is insufficient. The app needs at least 2–4GB during schema indexing. OOM kills manifest as silent 500 errors.

          Key Files
          FilePurposeCloudronManifest.jsonhealthCheckPath, runtimeDirs, memory limit, addonsstart.shBridges Cloudron env vars (CLOUDRON_MONGODB_URL → MONGODB_URI), generates NEXTAUTH_SECRET on first runDockerfileNode 22 via n, two-stage build, prod-only depstina/database.tsMongoDB adapter configpages/api/tina/[...routes].tsGraphQL endpoint with AuthJsBackendAuthProviderpages/api/auth/[...nextauth].tsNextAuth login handlerpages/api/health.tsCloudron health check

          Advice for Custom App Installers

          Start with Node 22. Don't waste time on ESM workarounds.
          Allocate 4GB RAM minimum for the app during setup.
          Use Docker Hub (or GHCR) as an intermediary for image pushes — never the Cloudron web upload.
          Test locally with podman run before every deploy. The Cloudron update cycle is 5–10 minutes.
          The schema indexing problem is the critical unsolved piece. TinaCMS expects tinacms build to run with database access, but this is difficult in Cloudron's immutable container model.

          Advice for Cloudron Packagers

          TinaCMS is not packaging-friendly. It conflates build-time code generation with runtime schema indexing. There's no clean separation.
          The MongoDB adapter (mongodb-level) works but adds ESM complexity. Consider whether SQLite with persistent storage (/app/data) might be simpler.
          tinacms build needs a running database. Either:

          Run it as a post-start hook before Next.js starts
          Or find a way to pre-generate the schema and load it at startup

          Auth is tightly coupled. tinacms-authjs expects both the GraphQL route and the NextAuth route to use the same TinaAuthJSOptions factory — which itself requires the database client.
          Memory: Budget 1GB steady-state, 2–4GB for indexing operations.

          Environment Reference
          Cloudron base: 4.2.0
          Node.js: 22.22.0 (via n)
          TinaCMS: 2.10.1
          Next.js: 14.2.35
          next-auth: 4.24.13
          tinacms-authjs: 5.0.9
          mongodb-level: (bundled via esbuild)
          pnpm: 10.30.x

          Posted in the hope of saving someone else 20 hours. If you've successfully packaged TinaCMS for Cloudron, please share your approach!

          timconsidineT Online
          timconsidineT Online
          timconsidine
          App Dev
          wrote last edited by
          #4

          @LoudLemur said:

          What We Built
          A Docker image based on cloudron/base:4.2.0

          Why 4.2.0 ?
          I use 5.0.0.
          Supports more recent Node

          If you're happy, share your repo and maybe someone can take a look.

          Indie app dev, scratching my itches, lover of Cloudron PaaS

          1 Reply Last reply
          2
          • L Offline
            L Offline
            LoudLemur
            wrote last edited by
            #5

            Hey, Tim! Thanks for looking.

            Why 4.2.0? Looking back, it is what the TinaCMS self-hosted starter's Dockerfile used, and we didn't think to question it until we were deep in ESM hell. We ended up having to install Node 22 via n and nuke the base image's Node 18, which is exactly the kind of thing a newer base image would have avoided. If 5.0.0 ships with Node 20+ that alone would eliminate Showstopper #5 (the ESM compatibility hydra that ate most of our time).
            The repo: Here it is: https://github.com/OrcVole/tinacms-cloudron
            Fair warning: it's in a "works up to the last mile" state. The Docker image builds, health checks pass, admin UI loads, auth works, and the GraphQL API returns JSON. But schema indexing into MongoDB never completes, so the editor can't actually load content. If someone familiar with TinaCMS internals (or Cloudron base 5.0.0) wants to take a crack at that final piece, the groundwork is all there.
            Would switching to base 5.0.0 and its native Node fix the indexing step too? That's the bit we never got past. The tinacms build --skip-cloud-checks command (without --skip-indexing) just prints "The service was stopped / Unable to build" with no useful error output.

            timconsidineT 1 Reply Last reply
            0
            • L LoudLemur

              Hey, Tim! Thanks for looking.

              Why 4.2.0? Looking back, it is what the TinaCMS self-hosted starter's Dockerfile used, and we didn't think to question it until we were deep in ESM hell. We ended up having to install Node 22 via n and nuke the base image's Node 18, which is exactly the kind of thing a newer base image would have avoided. If 5.0.0 ships with Node 20+ that alone would eliminate Showstopper #5 (the ESM compatibility hydra that ate most of our time).
              The repo: Here it is: https://github.com/OrcVole/tinacms-cloudron
              Fair warning: it's in a "works up to the last mile" state. The Docker image builds, health checks pass, admin UI loads, auth works, and the GraphQL API returns JSON. But schema indexing into MongoDB never completes, so the editor can't actually load content. If someone familiar with TinaCMS internals (or Cloudron base 5.0.0) wants to take a crack at that final piece, the groundwork is all there.
              Would switching to base 5.0.0 and its native Node fix the indexing step too? That's the bit we never got past. The tinacms build --skip-cloud-checks command (without --skip-indexing) just prints "The service was stopped / Unable to build" with no useful error output.

              timconsidineT Online
              timconsidineT Online
              timconsidine
              App Dev
              wrote last edited by timconsidine
              #6

              @LoudLemur said:

              it's in a "works up to the last mile" state.

              I've got a few of those, so understood 😄

              @LoudLemur said:

              Would switching to base 5.0.0 and its native Node fix the indexing step too?

              I've found that the answer to that type of question is only ever discovered by trying it ! 😄

              I have a few other projects on/behind, but I might take a look. But please don't let that stop anyone else doing so.

              Indie app dev, scratching my itches, lover of Cloudron PaaS

              1 Reply Last reply
              1

              Hello! It looks like you're interested in this conversation, but you don't have an account yet.

              Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

              With your input, this post could be even better 💗

              Register Login
              Reply
              • Reply as topic
              Log in to reply
              • Oldest to Newest
              • Newest to Oldest
              • Most Votes


              • Login

              • Don't have an account? Register

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Bookmarks
              • Search