Doory, a browser design editor you can run on your own server
Open source canva alternative
At a glance
- What is it?
- Doory is a self-hostable alternative to Canva: a browser editor for posters, social posts, slides and invitations that exports to PNG, JPG, SVG, PDF, MP4 and GIF, with no paid plan and no account needed to start. It is a Django and TypeScript application shipped as a Docker Compose stack, and its own README calls it a young project with ten starter templates.
- Who is it for?
- Doory suits an organisation that needs a design tool it controls, that wants templates and brand kits kept in house, and that has someone willing to run a Docker Compose stack with PostgreSQL, a Django API and an nginx frontend.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What it is, and what the README admits about it
Doory is a design editor that runs in the browser, handling posters, social posts, stories, slides, invitations, resumes, thumbnails and business cards. You start from a template or a blank page, edit everything on it, and export PNG, JPG, SVG, PDF, MP4 or GIF. There is no paid plan, you do not need an account to start, and you can run it on your own server with Docker or without it.
The README is unusually direct about the project's maturity. It is a young project: the editor is complete, the template library is small, with ten starter templates, and bug reports are very welcome.
That single paragraph tells you a lot about what you are getting. The hard part, a browser-based design editor, is built. The part that makes commercial products like this valuable, the library of professionally designed templates, is what is thin, and the README says the ten starters follow the layout of the best-selling templates in their category, use open-licensed fonts and, where there is a photo, a CC0 one, and that everything on them can be edited. Admins can add more in the admin site.
The homepage is doory.art, the last push was on 2026-10-14, the default branch is main, and the repository has no GitHub releases. The licence is a custom one that GitHub cannot classify, and the repository carries a NOTICE file and a THIRD_PARTY.md alongside the LICENSE, which is what you would expect from a project that ships open-licensed fonts, CC0 audio and downloaded icon packs.
The comparison in the repository description is a one-liner, open source canva alternative, and the honest way to read that is as a statement about ownership and cost rather than about feature parity. What you are getting is the editor, not the catalogue.
The feature set, and the parts that run in the browser
The feature table is dense, and a few entries are worth pulling out because they describe work that happens on the client rather than on a server.
The editor layout is described in terms of rails and panels. Tools sit in a rail on the left and open as panels, and the toolbar above the page changes with what you select. That is a deliberate interaction model for a pointer-driven canvas in a browser, and it is the kind of thing that is much easier to use than a modal dialog per operation.
The Layers panel allows renaming, locking, hiding, grouping and reordering anything, and a right-click menu to copy, duplicate and arrange. Right-click menus on canvas objects are a direct transfer from desktop design tools, which is a good sign for anyone who has used one.
The animation panel is the most substantial feature. It offers enter, exit and emphasis animations, page transitions, music and sound effects, and the result can be presented or exported as a video or GIF. The counts are given precisely in the table: 27 enter and exit animations, 12 emphasis animations, 16 page transitions, 24 music loops and 88 sound effects, which are CC0, plus voiceover recording.
The Photos row contains the claim that matters most for a self-hosted deployment: background removal that runs in the browser. The implication is that the model is downloaded once and inference happens on the client, which is why the sync_models management command exists to fetch a background removal model, and why the .env file notes that a new site has no model without it.
Stock photo search is the one place the tool talks to someone else's service, and it needs a key for Unsplash or Pexels. Everything else, text with curved text, effects and font pairings, elements including shapes, lines, arrows, about 25,000 icons, emoji, illustrations, stickers and QR codes, and the layout features of alignment guides, snapping, rulers and several pages per design where each page can be its own size, runs locally.
Export is PNG, JPG, SVG, PDF, MP4, WebM and GIF, with downloads made in the browser and print PDFs that can have bleed and crop marks. The bleed and crop marks detail is a print-shop concern, and it is the kind of thing that separates a tool built for screen sharing from one built for a print run.
Self-hosting it, and the two containers that matter
The self-hosting section is four commands:
cp .env.example .env # set DJANGO_SECRET_KEY (openssl rand -base64 48) and POSTGRES_PASSWORD
docker compose up -d --build
docker compose exec api python manage.py createsuperuser # your admin account; nothing creates one for youThen you open http://localhost:8080 and start designing. The web container serves the app and forwards /api and /ws to the backend, so the browser only ever talks to one address.
That last point is a real design decision and the compose file's header comment makes the topology explicit: PostgreSQL plus an API running gunicorn, plus a real-time server running uvicorn with WebSockets for co-editing, plus a web service running nginx that serves the SPA and proxies the API. Redis is optional and sits behind a compose profile.
The separation of the API from the real-time server is there for the collaboration features. Share links that view, comment or edit with an optional password, pinned comments, version history and real-time co-editing are listed in the Together row, and WebSockets are how the co-editing and the comments work. So the stack is not a monolith, and the reason is the feature set rather than architectural fashion.
The database service is postgres:16-alpine with a healthcheck and a named volume, and the API depends on it with the condition service_healthy, which is what stops the API from starting against a database that is not ready. The API container also sets init: true, with a comment explaining that it reaps the Chromium child processes of the PDF export, and it runs with the no-new-privileges security option.
The .env.example file shows the required settings and their reasons. SITE_URL is the public address with scheme and no trailing slash, used in emails and CSRF checks, and DJANGO_SECRET_KEY must be a long random value such as openssl rand -base64 48, with a note that changing it signs everyone out. POSTGRES_PASSWORD has a specific constraint, keep it URL-safe with letters and digits only, because it is embedded in DATABASE_URL. DJANGO_ALLOWED_HOSTS is the host names the API answers to, comma separated.
There is a security note about the reverse proxy count. NUM_PROXIES is set to 1 for the bundled nginx, and you add one for each extra proxy that does not rewrite X-Forwarded-For, which is a detail that matters for rate limiting and the kind of thing that is usually left undocumented.
For the front door, the compose header says to set WEB_BIND to 127.0.0.1 to keep the site private to a reverse proxy running on the same host, and to put a TLS-terminating reverse proxy in front of the web service for anything public.
Seeding the content and the settings worth knowing
A new site starts empty, and the README is direct about what that means. The .env file states that without the first-run content a new site has no icons, emoji or illustrations, no fonts besides the system ones and no background-removal model.
The remedy is a set of management commands, which can be run once against a running instance:
docker compose exec api python manage.py seed_gallery # template categories
docker compose exec api python manage.py sync_fonts --popular 100
docker compose exec api python manage.py seed_templates # the starter templates (add --update to refresh them)
docker compose exec api python manage.py seed_elements # shapes and graphics
docker compose exec api python manage.py sync_element_packs # icons, emoji and illustrations (download)
docker compose exec api python manage.py sync_models # background removal model
docker compose exec api python manage.py sync_audio # music and sound effectsAlternatively you can set the DOORY_SYNC_* and DOORY_SEED_TEMPLATES options in .env to true and the API container does it on start. The .env file notes that these flags run the downloads inside the API container before it starts serving, and that a failed download is logged and never stops the server. That is a deliberate choice: a missing font pack should not take the site down, but it should be visible in the logs.
The settings table is where the operational decisions live. SECURE_SSL_REDIRECT and SECURE_COOKIES default to false so you can try Doory over plain http://localhost, and both should be true behind a TLS-terminating proxy. EMAIL_URL and DEFAULT_FROM_EMAIL configure SMTP, for example smtp+tls://user:[email protected]:587, and without it emails are printed to the API log, which is a sensible development default and a trap in production if you forget. WEB_PORT and WEB_BIND control where the site is published, defaulting to 0.0.0.0:8080.
And then there is INSTALL_CHROMIUM, which is false to skip the headless browser that server-side PDF export needs, at a cost of about 400 MB in the image. That is a large fraction of the image for one feature, and it is the setting to think about before deploying.
For development without Docker, the Makefile has the same story in a different form. make setup creates the virtualenv, installs the backend requirements, copies the .env, migrates the database and installs the frontend dependencies. make dev-api runs the Django API on port 8000, make dev-web runs the Vite dev server on port 5173 and proxies /api to the API, and make test runs both suites, pytest for the backend and vitest for the frontend. There is also a make content target, with a FONT_FAMILIES variable defaulting to 100 out of a curated list of 253 font families, and a make seed target that can create an optional first administrator from ADMIN_EMAIL and ADMIN_PASSWORD.
Editorial conclusion
Doory suits an organisation that needs a design tool it controls, that wants templates and brand kits kept in house, and that has someone willing to run a Docker Compose stack with PostgreSQL, a Django API and an nginx frontend. It is the wrong choice if you want a broad template library, because ten starter templates ship and the rest is left to the admin, and it is the wrong choice if you cannot host the first-run downloads, because a fresh install has no fonts, icons, emoji, illustrations or background-removal model until the sync commands run. Before deploying, read the .env settings table and the note about headless Chromium, since server-side PDF export adds roughly 400 MB to the image, and check the licence file yourself, because the repository's licence is not classified.
Frequently asked questions
What is Doory and what does it replace?
It is a design editor that runs in the browser for posters, social posts, stories, slides, invitations, resumes, thumbnails and business cards, with export to PNG, JPG, SVG, PDF, MP4 or GIF. The repository describes it as an open source Canva alternative, with no paid plan and no account needed to start, and it can be run on your own server with Docker or without it.
How do I self-host Doory?
Copy .env.example to .env and set DJANGO_SECRET_KEY and POSTGRES_PASSWORD, run docker compose up -d --build, then create your admin account with docker compose exec api python manage.py createsuperuser. The site is then published on http://localhost:8080, and the web container forwards /api and /ws to the backend so the browser talks to one address.
Why does a fresh Doory install have no icons or fonts?
A new site starts empty, so you need the first-run content. Either run the management commands such as seed_templates, sync_fonts, sync_element_packs, sync_models and sync_audio, or set the DOORY_SYNC_* and DOORY_SEED_TEMPLATES options in .env so the API container does the downloads on start, with a failed download logged rather than stopping the server.
Which features run in the browser rather than on the server?
Background removal runs in the browser, and the downloads are made in the browser too. The Share menu handles sharing, downloads and presenting in one place, and print PDFs can have bleed and crop marks. Stock photo search is the one feature that reaches an external service, needing an Unsplash or Pexels key.
What is the INSTALL_CHROMIUM setting for?
It controls whether a headless browser is built into the API image for server-side PDF export, at a cost of about 400 MB. Setting it to false skips the headless browser, and the .env file gives that as the setting to turn off if you do not need server-side PDF export.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/shaongitbd-doory)Was this useful?