A modern blogging platform designed specifically for the tech community. Built for developers, by developers.
TechDiary is a feature-rich blogging platform that empowers developers and tech enthusiasts to share knowledge, document their journey, and build meaningful connections within the tech community. With support for multiple languages, intuitive writing tools, and powerful engagement features, TechDiary creates the perfect environment for technical content creation and discovery.
- Rich Markdown editor with Markdoc parsing, live preview, and auto-save
- Drag-and-drop image upload with cropping (Cloudinary and Cloudflare R2)
- Series support for organizing related articles
- Draft management with periodic autosave
- SEO with meta tags and structured data
- Code snippets with multiple files, browsing, and sharing (
/gists)
- Bengali and English UI (dictionary for Bengali; English uses keys as fallback)
- Localized formatting for dates and numbers where applicable
- Language preference persisted via cookie and client state
- Full-text search powered by Meilisearch
- Filtering by tags, authors, and dates
- Fast, typo-tolerant queries
- Emoji reactions (Love, Fire, Wow, Haha, Cry, Unicorn)
- Threaded comments
- Bookmarks and following authors
- In-app notifications with background processing (Inngest)
- Realtime updates over the Pusher protocol; use Pusher or self-host Soketi (open-source, drop-in compatible) for selective UI refresh
- WorkOS AuthKit as the primary sign-in path
- GitHub OAuth available as a legacy alternative
- Secure sessions stored in PostgreSQL with HTTP-only cookies
- Dark/light theme
- Responsive layout
- Web app manifest and service worker registration for installable / app-like behavior
- Next.js 16 — App Router, React Server Components, Turbopack in dev (
next dev --turbo) - React 19
- TypeScript
- Tailwind CSS 4
- shadcn/ui — Radix-based components
- Next.js Server Actions — primary server API surface
- SQLKit — lightweight query builder for most database access
- Drizzle ORM — schema and migrations only (
db:generate/db:push) - PostgreSQL — primary database
- Meilisearch — search index and queries
- Cloudflare R2 — S3-compatible uploads (presigned URLs)
- Cloudinary — image URLs and transforms (legacy paths)
- Inngest — scheduled jobs (e.g. article cleanup) and notification queueing
- Pusher-compatible WebSockets — managed Pusher or self-hosted Soketi (same wire protocol and client libraries; point
PUSHER_*/NEXT_PUBLIC_PUSHER_*at your Soketi host)
- Jotai — client UI state
- TanStack Query — server state and cache invalidation
- React Hook Form + Zod — forms and validation
- Bun — scripts and package management (Node-compatible)
- ESLint —
eslint-config-next - Prettier — formatting
- Bun (recommended) or Node.js 22+ (aligned with dev dependencies)
- PostgreSQL 14+
- Meilisearch instance
- WorkOS account (AuthKit) for primary login, and/or GitHub OAuth app for legacy flow
- Cloudinary and/or Cloudflare R2 for uploads (see env below)
Create a .env.local in the project root. Required variables are validated in src/env.ts at runtime; WorkOS is used by AuthKit alongside those (see CLAUDE.md).
# Database
DATABASE_URL="postgresql://username:password@localhost:5432/techdiary"
# WorkOS (primary auth — AuthKit)
WORKOS_API_KEY=""
WORKOS_CLIENT_ID=""
WORKOS_COOKIE_PASSWORD=""
NEXT_PUBLIC_WORKOS_REDIRECT_URI="http://localhost:3000/api/auth/wos/callback"
# GitHub OAuth (legacy)
GITHUB_CLIENT_ID=""
GITHUB_CLIENT_SECRET=""
GITHUB_CALLBACK_URL="http://localhost:3000/api/auth/github/callback"
# Unsplash (required by env schema — used for integrations)
UNSPLASH_API_KEY=""
# Cloudinary
CLOUDINARY_URL="cloudinary://api_key:api_secret@cloud_name"
# Cloudflare R2 (S3-compatible — names match src/env.ts)
S3_ENDPOINT=""
S3_REGION="auto"
S3_BUCKET=""
S3_ACCESS_KEY_ID=""
S3_ACCESS_SECRET=""
# Meilisearch
MEILISEARCH_ADMIN_API_KEY=""
NEXT_PUBLIC_MEILISEARCH_API_HOST="http://localhost:7700"
NEXT_PUBLIC_MEILISEARCH_SEARCH_API_KEY=""
# Inngest (optional in schema — omit or leave empty for local-only)
INNGEST_EVENT_KEY=""
INNGEST_SIGNING_KEY=""
# Realtime: Pusher SaaS or self-hosted Soketi (drop-in Pusher replacement — same env names)
PUSHER_WS_HOST=""
PUSHER_APP_ID=""
PUSHER_APP_KEY=""
PUSHER_APP_SECRET=""
NEXT_PUBLIC_PUSHER_APP_KEY=""
NEXT_PUBLIC_PUSHER_WS_HOST=""-
Clone the repository
git clone https://github.com/techdiary-dev/techdiary.dev.git cd techdiary.dev -
Install dependencies
bun install
-
Database
bun run db:generate # generate migrations from schema when you change Drizzle tables bun run db:push # apply schema to your database
-
Development server
bun run dev
| Command | Description |
|---|---|
bun run dev |
Dev server with Turbopack |
bun run build |
Production build |
bun run start |
Production server |
bun run lint |
ESLint |
bun run db:generate |
Drizzle migrations from schemas.ts |
bun run db:push |
Push schema to DB |
bun run db:studio |
Drizzle Studio |
bun run play |
Backend playground (src/backend/play.ts) |
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── (home)/ # Homepage and feed
│ │ ├── (dashboard-editor)/ # Editor-related dashboard routes
│ │ ├── dashboard/ # Dashboard layout
│ │ ├── gists/ # Gists (list, create, view)
│ │ ├── [username]/ # Profiles and article pages
│ │ ├── api/ # API routes (auth, storage, etc.)
│ │ └── sitemaps/ # Dynamic sitemaps
│ ├── backend/
│ │ ├── models/ # Domain types and action contracts
│ │ ├── persistence/ # Drizzle schemas, SQLKit repositories, PG client
│ │ └── services/ # Server actions, inputs (Zod), integrations
│ ├── components/ # UI and feature components
│ ├── hooks/
│ ├── i18n/
│ ├── lib/
│ ├── store/ # Jotai atoms
│ └── styles/
├── docs/ # Internal docs (components, hooks, PRD)
├── public/
└── migrations/ # Generated SQL migrations
- Server actions return a consistent
ActionResponse<T>union; TanStack Query calls actions directly from the client where appropriate. - Caching uses Next.js Cache Components / Partial Prerendering; user-specific data stays dynamic (cookies, session).
- Article soft-delete uses
delete_scheduled_at; cleanup runs on an Inngest schedule.
- Component docs
- Hooks docs
- PRD
- Agent / contributor reference: CLAUDE.md (commands, env vars, auth flow, caching rules)
- Runtime: Node-compatible host for Next.js (e.g. Vercel) or your platform of choice.
- Data: Managed PostgreSQL; Meilisearch (cloud or self-hosted).
- Auth: Set WorkOS production redirect URI and cookie secret; align
NEXT_PUBLIC_WORKOS_REDIRECT_URIwith your domain. - Storage: R2 credentials and/or Cloudinary for production URLs.
- Inngest: Configure event and signing keys for production workers.
- Fork the repository and create a branch for your change.
- Follow existing TypeScript, ESLint, and formatting conventions.
- There is no automated test suite in this repo; use
bun run playto exercise backend code when needed. - Open a pull request with a clear description.
For deeper conventions (actions, repositories, i18n), see CLAUDE.md.
Next.js, shadcn/ui, Meilisearch, WorkOS, and the open-source ecosystem this project builds on.
- Site: techdiary.dev
- Community: Discord
- Issues: GitHub
- Email: hello@techdiary.dev
Built with care by the TechDiary team
