Open-source social media scheduling for 30+ platforms, with a public API, SDK and MCP server.
See the code
Open-source social media scheduling for 30+ platforms.
Plan, compose, and publish from one calendar, with a public API and SDK for automation
and an optional AI assist for checking and rewriting captions.
Quick Start · Features · Platforms · Architecture · Self-Hosting · Contributing · License
Scheduling and publishing
Composer
Security and account protection
Optional AI (off unless you provide a key)
OPENAI_API_KEY, or a per-org key you bring yourself (BYO)Collaboration and automation
/public/v1 and the @postsider/node package) for programmatic use@postsider/mcp33 connectors ship in the box. Each one is a self-contained provider class in
libraries/nestjs-libraries/src/integrations/social/,
so the list below is exactly what the code registers, nothing aspirational.
| Category | Platforms |
|---|---|
| Social | X, LinkedIn (profiles), LinkedIn (pages), Facebook, Instagram (via Facebook), Instagram (standalone login), Threads, YouTube, TikTok, Pinterest, Bluesky, Mastodon, Nostr, Farcaster, Lemmy, Twitch, Dribbble, Google Business Profile, Whop, Moltbook |
| Chat | Discord, Slack, Telegram |
| Blogs and newsletters | Dev.to, Hashnode, Medium, WordPress, Ghost, Blogger, Mataroa, Write.as, Notion, Listmonk |
You only configure OAuth credentials for the platforms you actually use, see
.env.example. Mastodon supports custom instances through the
standard Mastodon connector.
Adding a platform means adding one provider class that extends SocialAbstract
and implements SocialProvider, then registering it in integration.manager.ts.
New connectors are the most welcome kind of pull request.
git clone https://github.com/lumizone/postsider.git
cd postsider
docker compose up -d
This pulls the published image ghcr.io/lumizone/postsider-app:latest, brings up
Postgres, Redis and Temporal alongside it, and applies database migrations on
startup. The app is served on http://localhost:4007.
Create the first admin account, then sign in (see First login):
docker exec -it postsider pnpm bootstrap
To build the image from source instead of pulling it, replace the image: line
for the postsider service in docker-compose.yaml with build: ..
# 1. Clone and install
git clone https://github.com/lumizone/postsider.git
cd postsider
pnpm install
# 2. Set up environment
cp .env.example .env
# Edit .env, at minimum set DATABASE_URL, REDIS_URL, JWT_SECRET
# 3. Apply the database schema
pnpm prisma-migrate-deploy
# 4. Create your first admin user
pnpm bootstrap
# 5. Start development servers (backend + orchestrator)
pnpm dev
# 6. In another terminal, start the frontend
pnpm dev:frontend
The backend runs on http://localhost:3000, the frontend on http://localhost:4200.
After running pnpm bootstrap, you receive a one-time password in the terminal. Sign in with admin@setup.local and that password, then you are prompted to set your real email and password.
PostSider is a pnpm monorepo with the following structure:
postsider/
├── apps/
│ ├── backend/ # NestJS REST API (auth, posts, integrations, billing)
│ ├── orchestrator/ # Temporal worker (scheduled publishing, token refresh)
│ ├── frontend/ # Next.js 15 dashboard (React 19, App Router)
│ ├── commands/ # CLI utilities (bootstrap, config)
│ └── sdk/ # Published npm package for the public API
├── libraries/
│ ├── nestjs-libraries/ # Shared backend logic (Prisma, integrations, uploads)
│ └── helpers/ # Lightweight utilities (auth, crypto, validation)
├── docker-compose.yaml # Production-ready stack
└── .env.example # Configuration reference
| Layer | Technology |
|---|---|
| Backend API | NestJS 11, TypeScript 5.5 |
| Frontend | Next.js 15, React 19, CSS Modules |
| Database | PostgreSQL + Prisma 6.5 |
| Cache / Queue | Redis 7 |
| Workflow Engine | Temporal (durable post scheduling, token refresh) |
| AI (optional) | OpenAI (Post Checker and caption rewrite) |
| Billing (optional) | Polar.sh (Merchant of Record) |
| Storage | Local filesystem or Cloudflare R2 |
| Auth | JWT + bcrypt, OAuth (GitHub, Google, Generic OIDC) |
| Monitoring | Sentry |
SocialProvider. Adding a new platform means adding one file.POLAR_ACCESS_TOKEN is set; AI features are enabled only when an OpenAI key is present (platform or BYO). With neither, every org is unlimited and AI is simply hidden.@postsider/sdk package wraps the public v1 endpoints for external consumers.All configuration lives in environment variables. See .env.example
for the full reference, and
docs.postsider.com/configuration/environment
for the annotated version.
| Variable | Description |
|---|---|
DATABASE_URL | PostgreSQL connection string |
REDIS_URL | Redis connection string |
JWT_SECRET | Random string for signing tokens (make it long and unique) |
FRONTEND_URL | Public URL where the dashboard is accessible |
NEXT_PUBLIC_BACKEND_URL | Public URL of the backend API |
By default, files are stored locally in ./uploads/. For cloud storage, set:
STORAGE_PROVIDER=cloudflare
CLOUDFLARE_ACCOUNT_ID=...
CLOUDFLARE_ACCESS_KEY=...
CLOUDFLARE_SECRET_ACCESS_KEY=...
CLOUDFLARE_BUCKETNAME=...
CLOUDFLARE_BUCKET_URL=...
Each platform requires its own OAuth credentials, registered in that provider's
developer portal. .env.example lists every variable, and
docs.postsider.com/channels/overview
walks through the per-platform setup. You only need to configure the platforms
you plan to use.
Operational guide with domain, TLS and backup notes: docs.postsider.com/self-hosting.
docker-compose.production.yaml runs the full stack in a single command:
Migrations run automatically at startup via prisma migrate deploy before the app starts.
Steps:
# 1. Copy the env template
cp .env.example .env.production
# 2. Fill in required values: DATABASE_URL, REDIS_URL, JWT_SECRET,
# FRONTEND_URL, NEXT_PUBLIC_BACKEND_URL, BACKEND_INTERNAL_URL,
# MINIO_ACCESS_KEY, MINIO_SECRET_KEY, POSTGRES_PASSWORD.
# Leave POLAR_ACCESS_TOKEN and OPENAI_API_KEY blank for self-host
# (billing becomes unlimited; AI features use user-supplied BYO keys).
# For each social platform you want, register an OAuth app on the
# provider's developer portal and fill in the matching CLIENT_ID /
# CLIENT_SECRET vars (see the "Social platform OAuth credentials"
# section in .env.example).
# Set NEXT_PUBLIC_BACKEND_URL=https://app.yourdomain.com and build
# the image (NEXT_PUBLIC_BACKEND_URL is baked into the JS bundle).
nano .env.production
# 3. Build the image (NEXT_PUBLIC_* vars are build-time ARGs)
source .env.production && docker compose -f docker-compose.production.yaml build \
--build-arg NEXT_PUBLIC_BACKEND_URL="$NEXT_PUBLIC_BACKEND_URL"
# 4. Start everything
docker compose -f docker-compose.production.yaml up -d
# 5. Create the first admin account
docker exec -it postsider-app pnpm bootstrap
# 6. Check logs
docker compose -f docker-compose.production.yaml logs -f postsider
The app is then available on port 5000 (put nginx or a reverse proxy in front for HTTPS).
docker compose -f docker-compose.production.yaml pull
docker compose -f docker-compose.production.yaml up -d
Migrations run automatically on each restart.
The critical data lives in PostgreSQL. Back up the postsider-postgres volume regularly:
docker exec postsider-postgres pg_dump -U postsider postsider_prod > backup.sql
# Run backend only
pnpm dev:backend
# Run frontend only
pnpm dev:frontend
# Run orchestrator only
pnpm dev:orchestrator
# Generate Prisma client after schema changes
pnpm prisma-generate
# Create a migration after schema changes
pnpm prisma-migrate-dev
# Apply pending migrations
pnpm prisma-migrate-deploy
# Build all apps
pnpm build
# Build SDK
pnpm build:sdk
@postsider/backend/*, @postsider/helpers/*, @postsider/nestjs-libraries/*, and so onDatabaseModuleSocialAbstract and implements SocialProviderapps/orchestrator/src/workflows/prisma migrate deploy on bootPostSider exposes a public REST API for programmatic access. Authenticate with your org's API key via the Authorization header.
npm install @postsider/node
import Postsider from '@postsider/node';
const client = new Postsider('your-api-key', 'https://your-instance.com');
// Create a post
await client.post({
type: 'schedule',
date: '2025-01-15T10:00:00',
posts: [{ integration: { id: 'channel-id' }, value: [{ content: 'Hello!' }] }],
});
// List posts
const posts = await client.postList({ page: 0, limit: 20 });
// List connected channels
const channels = await client.integrations();
PostSider ships an MCP server so AI agents (Claude Code, Claude Desktop, Codex, and any MCP-compatible client) can use the platform through the public API: list channels, schedule and publish posts, upload media, and read analytics. It is a thin, dependency-light wrapper over the public API.
pnpm --filter @postsider/mcp build
Then point your agent at apps/mcp/dist/index.js with POSTSIDER_API_KEY (and
POSTSIDER_API_URL for a self-hosted instance). See
apps/mcp/README.md for client config snippets and the
full tool list, or
docs.postsider.com/agent/mcp/overview
for the hosted walkthrough.
Contributions are welcome. Here is how to get started:
git checkout -b feature/my-featurepnpm run build:backendstrictNullChecks for now; PRs to fix null-safety are welcome).prettierrc in root)strictNullChecks across the codebasePostSider is licensed under the GNU Affero General Public License v3.0.
This means you can use, modify, and distribute PostSider freely, but if you run a modified version as a network service, you must make your source code available to users of that service.
5 commits
TypeScript
93.5%
CSS
4.5%
JavaScript
1.3%
Open-source social media scheduling for 30+ platforms, with a public API, SDK and MCP server.
See the code
Open-source social media scheduling for 30+ platforms.
Plan, compose, and publish from one calendar, with a public API and SDK for automation
and an optional AI assist for checking and rewriting captions.
Quick Start · Features · Platforms · Architecture · Self-Hosting · Contributing · License
Scheduling and publishing
Composer
Security and account protection
Optional AI (off unless you provide a key)
OPENAI_API_KEY, or a per-org key you bring yourself (BYO)Collaboration and automation
/public/v1 and the @postsider/node package) for programmatic use@postsider/mcp33 connectors ship in the box. Each one is a self-contained provider class in
libraries/nestjs-libraries/src/integrations/social/,
so the list below is exactly what the code registers, nothing aspirational.
| Category | Platforms |
|---|---|
| Social | X, LinkedIn (profiles), LinkedIn (pages), Facebook, Instagram (via Facebook), Instagram (standalone login), Threads, YouTube, TikTok, Pinterest, Bluesky, Mastodon, Nostr, Farcaster, Lemmy, Twitch, Dribbble, Google Business Profile, Whop, Moltbook |
| Chat | Discord, Slack, Telegram |
| Blogs and newsletters | Dev.to, Hashnode, Medium, WordPress, Ghost, Blogger, Mataroa, Write.as, Notion, Listmonk |
You only configure OAuth credentials for the platforms you actually use, see
.env.example. Mastodon supports custom instances through the
standard Mastodon connector.
Adding a platform means adding one provider class that extends SocialAbstract
and implements SocialProvider, then registering it in integration.manager.ts.
New connectors are the most welcome kind of pull request.
git clone https://github.com/lumizone/postsider.git
cd postsider
docker compose up -d
This pulls the published image ghcr.io/lumizone/postsider-app:latest, brings up
Postgres, Redis and Temporal alongside it, and applies database migrations on
startup. The app is served on http://localhost:4007.
Create the first admin account, then sign in (see First login):
docker exec -it postsider pnpm bootstrap
To build the image from source instead of pulling it, replace the image: line
for the postsider service in docker-compose.yaml with build: ..
# 1. Clone and install
git clone https://github.com/lumizone/postsider.git
cd postsider
pnpm install
# 2. Set up environment
cp .env.example .env
# Edit .env, at minimum set DATABASE_URL, REDIS_URL, JWT_SECRET
# 3. Apply the database schema
pnpm prisma-migrate-deploy
# 4. Create your first admin user
pnpm bootstrap
# 5. Start development servers (backend + orchestrator)
pnpm dev
# 6. In another terminal, start the frontend
pnpm dev:frontend
The backend runs on http://localhost:3000, the frontend on http://localhost:4200.
After running pnpm bootstrap, you receive a one-time password in the terminal. Sign in with admin@setup.local and that password, then you are prompted to set your real email and password.
PostSider is a pnpm monorepo with the following structure:
postsider/
├── apps/
│ ├── backend/ # NestJS REST API (auth, posts, integrations, billing)
│ ├── orchestrator/ # Temporal worker (scheduled publishing, token refresh)
│ ├── frontend/ # Next.js 15 dashboard (React 19, App Router)
│ ├── commands/ # CLI utilities (bootstrap, config)
│ └── sdk/ # Published npm package for the public API
├── libraries/
│ ├── nestjs-libraries/ # Shared backend logic (Prisma, integrations, uploads)
│ └── helpers/ # Lightweight utilities (auth, crypto, validation)
├── docker-compose.yaml # Production-ready stack
└── .env.example # Configuration reference
| Layer | Technology |
|---|---|
| Backend API | NestJS 11, TypeScript 5.5 |
| Frontend | Next.js 15, React 19, CSS Modules |
| Database | PostgreSQL + Prisma 6.5 |
| Cache / Queue | Redis 7 |
| Workflow Engine | Temporal (durable post scheduling, token refresh) |
| AI (optional) | OpenAI (Post Checker and caption rewrite) |
| Billing (optional) | Polar.sh (Merchant of Record) |
| Storage | Local filesystem or Cloudflare R2 |
| Auth | JWT + bcrypt, OAuth (GitHub, Google, Generic OIDC) |
| Monitoring | Sentry |
SocialProvider. Adding a new platform means adding one file.POLAR_ACCESS_TOKEN is set; AI features are enabled only when an OpenAI key is present (platform or BYO). With neither, every org is unlimited and AI is simply hidden.@postsider/sdk package wraps the public v1 endpoints for external consumers.All configuration lives in environment variables. See .env.example
for the full reference, and
docs.postsider.com/configuration/environment
for the annotated version.
| Variable | Description |
|---|---|
DATABASE_URL | PostgreSQL connection string |
REDIS_URL | Redis connection string |
JWT_SECRET | Random string for signing tokens (make it long and unique) |
FRONTEND_URL | Public URL where the dashboard is accessible |
NEXT_PUBLIC_BACKEND_URL | Public URL of the backend API |
By default, files are stored locally in ./uploads/. For cloud storage, set:
STORAGE_PROVIDER=cloudflare
CLOUDFLARE_ACCOUNT_ID=...
CLOUDFLARE_ACCESS_KEY=...
CLOUDFLARE_SECRET_ACCESS_KEY=...
CLOUDFLARE_BUCKETNAME=...
CLOUDFLARE_BUCKET_URL=...
Each platform requires its own OAuth credentials, registered in that provider's
developer portal. .env.example lists every variable, and
docs.postsider.com/channels/overview
walks through the per-platform setup. You only need to configure the platforms
you plan to use.
Operational guide with domain, TLS and backup notes: docs.postsider.com/self-hosting.
docker-compose.production.yaml runs the full stack in a single command:
Migrations run automatically at startup via prisma migrate deploy before the app starts.
Steps:
# 1. Copy the env template
cp .env.example .env.production
# 2. Fill in required values: DATABASE_URL, REDIS_URL, JWT_SECRET,
# FRONTEND_URL, NEXT_PUBLIC_BACKEND_URL, BACKEND_INTERNAL_URL,
# MINIO_ACCESS_KEY, MINIO_SECRET_KEY, POSTGRES_PASSWORD.
# Leave POLAR_ACCESS_TOKEN and OPENAI_API_KEY blank for self-host
# (billing becomes unlimited; AI features use user-supplied BYO keys).
# For each social platform you want, register an OAuth app on the
# provider's developer portal and fill in the matching CLIENT_ID /
# CLIENT_SECRET vars (see the "Social platform OAuth credentials"
# section in .env.example).
# Set NEXT_PUBLIC_BACKEND_URL=https://app.yourdomain.com and build
# the image (NEXT_PUBLIC_BACKEND_URL is baked into the JS bundle).
nano .env.production
# 3. Build the image (NEXT_PUBLIC_* vars are build-time ARGs)
source .env.production && docker compose -f docker-compose.production.yaml build \
--build-arg NEXT_PUBLIC_BACKEND_URL="$NEXT_PUBLIC_BACKEND_URL"
# 4. Start everything
docker compose -f docker-compose.production.yaml up -d
# 5. Create the first admin account
docker exec -it postsider-app pnpm bootstrap
# 6. Check logs
docker compose -f docker-compose.production.yaml logs -f postsider
The app is then available on port 5000 (put nginx or a reverse proxy in front for HTTPS).
docker compose -f docker-compose.production.yaml pull
docker compose -f docker-compose.production.yaml up -d
Migrations run automatically on each restart.
The critical data lives in PostgreSQL. Back up the postsider-postgres volume regularly:
docker exec postsider-postgres pg_dump -U postsider postsider_prod > backup.sql
# Run backend only
pnpm dev:backend
# Run frontend only
pnpm dev:frontend
# Run orchestrator only
pnpm dev:orchestrator
# Generate Prisma client after schema changes
pnpm prisma-generate
# Create a migration after schema changes
pnpm prisma-migrate-dev
# Apply pending migrations
pnpm prisma-migrate-deploy
# Build all apps
pnpm build
# Build SDK
pnpm build:sdk
@postsider/backend/*, @postsider/helpers/*, @postsider/nestjs-libraries/*, and so onDatabaseModuleSocialAbstract and implements SocialProviderapps/orchestrator/src/workflows/prisma migrate deploy on bootPostSider exposes a public REST API for programmatic access. Authenticate with your org's API key via the Authorization header.
npm install @postsider/node
import Postsider from '@postsider/node';
const client = new Postsider('your-api-key', 'https://your-instance.com');
// Create a post
await client.post({
type: 'schedule',
date: '2025-01-15T10:00:00',
posts: [{ integration: { id: 'channel-id' }, value: [{ content: 'Hello!' }] }],
});
// List posts
const posts = await client.postList({ page: 0, limit: 20 });
// List connected channels
const channels = await client.integrations();
PostSider ships an MCP server so AI agents (Claude Code, Claude Desktop, Codex, and any MCP-compatible client) can use the platform through the public API: list channels, schedule and publish posts, upload media, and read analytics. It is a thin, dependency-light wrapper over the public API.
pnpm --filter @postsider/mcp build
Then point your agent at apps/mcp/dist/index.js with POSTSIDER_API_KEY (and
POSTSIDER_API_URL for a self-hosted instance). See
apps/mcp/README.md for client config snippets and the
full tool list, or
docs.postsider.com/agent/mcp/overview
for the hosted walkthrough.
Contributions are welcome. Here is how to get started:
git checkout -b feature/my-featurepnpm run build:backendstrictNullChecks for now; PRs to fix null-safety are welcome).prettierrc in root)strictNullChecks across the codebasePostSider is licensed under the GNU Affero General Public License v3.0.
This means you can use, modify, and distribute PostSider freely, but if you run a modified version as a network service, you must make your source code available to users of that service.
5 commits
TypeScript
93.5%
CSS
4.5%
JavaScript
1.3%