Hosted (Render)
Render reads render.yaml at the repo root, which declares the full GiftWrapt stack: a managed Postgres database, an image-runtime web service that pulls ghcr.io/shawnphoffman/giftwrapt:latest, five Cron Jobs (one per /api/cron/* endpoint), and the env-var wiring between them.
Deploy
Section titled “Deploy”-
Click the deploy button above. Render reads the blueprint and creates the database, web service, and all five cron jobs.
-
First boot.
DATABASE_URLis wired automatically.BETTER_AUTH_SECRETandCRON_SECRETare auto-generated. Migrations run on the first start via the entrypoint. -
Set
BETTER_AUTH_URL. After the first deploy completes, set this on the web service to your Render-assigned URL (e.g.https://giftwrapt.onrender.com) or your custom domain. Redeploy. -
Sign up. The first user to register is auto-promoted to admin.
Optional Features
Section titled “Optional Features”Image uploads: fill in the STORAGE_* vars on the web service. Render leaves them as sync: false so it prompts at deploy time; you can also add them later. Recipes for Cloudflare R2, AWS S3, Supabase Storage, MinIO, etc. live in Storage.
Email (Resend): add RESEND_API_KEY and RESEND_FROM_EMAIL on the web service.
AI suggestions: see Suggestions (AI) for provider env vars.
Cron Jobs
Section titled “Cron Jobs”render.yaml ships all five cron services configured with daily UTC schedules:
| Endpoint | Schedule |
|---|---|
/api/cron/cleanup-verification | 0 3 * * * |
/api/cron/intelligence-recommendations | 0 4 * * * |
/api/cron/item-scrape-queue | 0 5 * * * |
/api/cron/auto-archive | 0 6 * * * |
/api/cron/birthday-emails | 0 7 * * * |
Each cron job uses the curlimages/curl image and inherits CRON_SECRET and BETTER_AUTH_URL from the web service via fromService: references. There’s no manual env paste.
To customize: edit the schedule: field on any cron service block in render.yaml and redeploy. To drop a job (e.g. you don’t have Resend configured and don’t need birthday emails) delete that service block.
Pinning a Version
Section titled “Pinning a Version”By default render.yaml pulls ghcr.io/shawnphoffman/giftwrapt:latest. Once you’re past the “does it work” phase, pin a specific tag (ghcr.io/shawnphoffman/giftwrapt:vX.Y.Z) so future image pushes don’t auto-deploy. Edit the image.url field in render.yaml and redeploy.
Custom Domain
Section titled “Custom Domain”Add the domain under the web service’s Settings → Custom Domains and point DNS per Render’s instructions. Once it’s live, set BETTER_AUTH_URL to the canonical HTTPS URL and redeploy.
If you serve from multiple hostnames, add the others to TRUSTED_ORIGINS instead of switching BETTER_AUTH_URL.
Updating
Section titled “Updating”Render pulls :latest on every deploy. Trigger a manual deploy from the dashboard to pick up a new image, or pin a specific tag and bump it explicitly when you want to upgrade.
Other Options
Section titled “Other Options”- Hosted (Railway) - one-click template with internal cron services
- Hosted (Vercel + Supabase) - the tried-and-true managed path
- Self-hosting with Docker - full control, runs anywhere