Linkwarden
Bookmark manager that saves pages and organizes links into collections.
- Replaces
-
Paid read-later services, such as Pocket.
All open-source alternatives to Pocket
- Difficulty
-
Difficulty: Medium
3 services (2 database or broker: postgres, meilisearch), 3 volume mounts, 2 env values to set, no elevated host access. Heuristic score 5 of 11: medium.
- Stack
TypeScript (language), PostgreSQL (database)
- Deployment
docker_compose
- Requirements
Not stated.
- License
-
AGPL-3.0(OSI-approved open source)Read from github.com/linkwarden/linkwarden/blob/952ac45/LICENSE.md
- Business model
-
Unknown
The README at the pinned commit does not state a business model, so it stays unknown.
Source: github.com/linkwarden/linkwarden/blob/952ac45/README.md, read on .
- Repository
GitHub stats
- Stars
- 20,176
- Forks
- 874
- Open issues and pull requests
- 688
- Last push
- 2026-10-19
- Latest release
- v2.16.3
- Released
- 2026-09-09
From the GitHub API on . These numbers are a snapshot, not live. GitHub detected the license as AGPL-3.0.
Compose file
services:
postgres:
image: postgres:16-alpine
env_file: .env
restart: always
volumes:
- ./pgdata:/var/lib/postgresql/data
linkwarden:
env_file: .env
environment:
- DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/postgres
restart: always
image: ghcr.io/linkwarden/linkwarden:latest
ports:
- 3000:3000
volumes:
- ./data:/data/data
depends_on:
- postgres
- meilisearch
meilisearch:
image: getmeili/meilisearch:v1.13.3
restart: always
env_file:
- .env
volumes:
- ./meili_data:/meili_data
From the app's own repository: github.com/linkwarden/linkwarden/blob/952ac45/docker-compose.yml.
Compose file from the app repository.
Install
- Docker with the Compose plugin (github.com/linkwarden/docs/blob/53e2dce/docs/self-hosting/setup.md)
A host with Docker and the Docker Compose plugin. This entry runs from a compose file.
- Save the compose file as docker-compose.yml (github.com/linkwarden/linkwarden/blob/952ac45/docker-compose.yml)
Use the compose file shown above.
- Save as .env next to the compose file (github.com/linkwarden/linkwarden/blob/952ac45/.env.sample)
# Full list of environment variables with descriptions can be found in the documentation: https://docs.linkwarden.app/self-hosting/environment-variables NEXTAUTH_URL=http://localhost:3000/api/v1/auth NEXTAUTH_SECRET= # Manual installation database settings # Example: DATABASE_URL=postgresql://user:password@localhost:5432/linkwarden DATABASE_URL= # Docker installation database settings POSTGRES_PASSWORD= # Additional Optional Settings PAGINATION_TAKE_COUNT= STORAGE_FOLDER= AUTOSCROLL_TIMEOUT= NEXT_PUBLIC_DISABLE_REGISTRATION= NEXT_PUBLIC_CREDENTIALS_ENABLED= DISABLE_NEW_SSO_USERS= MAX_LINKS_PER_USER= ARCHIVE_TAKE_COUNT= BROWSER_TIMEOUT= BROWSER_LIFECYCLE= IGNORE_URL_SIZE_LIMIT= NEXT_PUBLIC_DEMO= NEXT_PUBLIC_DEMO_USERNAME= NEXT_PUBLIC_DEMO_PASSWORD= NEXT_PUBLIC_ADMIN= NEXT_PUBLIC_MAX_FILE_BUFFER= PDF_MAX_BUFFER= SCREENSHOT_MAX_BUFFER= READABILITY_MAX_BUFFER= PREVIEW_MAX_BUFFER= MONOLITH_MAX_BUFFER= MONOLITH_CUSTOM_OPTIONS= IMPORT_LIMIT= PLAYWRIGHT_LAUNCH_OPTIONS_EXECUTABLE_PATH= PLAYWRIGHT_WS_URL= MAX_WORKERS= DISABLE_BROWSER= NEXT_PUBLIC_RSS_POLLING_INTERVAL_MINUTES= RSS_SUBSCRIPTION_LIMIT_PER_USER= TEXT_CONTENT_LIMIT= SEARCH_FILTER_LIMIT= INDEX_TAKE_COUNT= MEILI_TIMEOUT= ALLOW_PRIVATE_NETWORK_ACCESS= ALLOW_INSECURE_TLS= NEXT_PUBLIC_USER_CONTENT_DOMAIN= NEXT_PUBLIC_MOBILE_APP_REDIRECT_ENABLED= # AI Settings NEXT_PUBLIC_OLLAMA_ENDPOINT_URL= OLLAMA_MODEL= # https://ai-sdk.dev/providers/openai-compatible-providers OPENAI_API_KEY= OPENAI_MODEL= # Optional: Set a custom OpenAI base URL and name (for third-party providers) CUSTOM_OPENAI_BASE_URL= CUSTOM_OPENAI_NAME= # https://sdk.vercel.ai/providers/ai-sdk-providers/azure AZURE_API_KEY= AZURE_RESOURCE_NAME= AZURE_MODEL= # https://sdk.vercel.ai/providers/ai-sdk-providers/anthropic ANTHROPIC_API_KEY= ANTHROPIC_MODEL= # https://github.com/OpenRouterTeam/ai-sdk-provider OPENROUTER_API_KEY= OPENROUTER_MODEL= # https://ai-sdk.dev/providers/ai-sdk-providers/perplexity PERPLEXITY_API_KEY= PERPLEXITY_MODEL= # MeiliSearch Settings MEILI_HOST= MEILI_MASTER_KEY= # AWS S3 Settings SPACES_KEY= SPACES_SECRET= SPACES_ENDPOINT= SPACES_BUCKET_NAME= SPACES_REGION= SPACES_FORCE_PATH_STYLE= # SMTP Settings NEXT_PUBLIC_EMAIL_PROVIDER= EMAIL_FROM= EMAIL_SERVER= BASE_URL= # Proxy settings PROXY= PROXY_USERNAME= PROXY_PASSWORD= PROXY_BYPASS= # PDF archive settings PDF_MARGIN_TOP= PDF_MARGIN_BOTTOM= ################# # SSO Providers # ################# # 42 School NEXT_PUBLIC_FORTYTWO_ENABLED= FORTYTWO_CUSTOM_NAME= FORTYTWO_CLIENT_ID= FORTYTWO_CLIENT_SECRET= # Apple NEXT_PUBLIC_APPLE_ENABLED= APPLE_CUSTOM_NAME= APPLE_CLIENT_ID= APPLE_TEAM_ID= APPLE_KEY_ID= APPLE_PRIVATE_KEY= APPLE_CLIENT_SECRET= # Atlassian NEXT_PUBLIC_ATLASSIAN_ENABLED= ATLASSIAN_CUSTOM_NAME= ATLASSIAN_CLIENT_ID= ATLASSIAN_CLIENT_SECRET= ATLASSIAN_SCOPE= # Auth0 NEXT_PUBLIC_AUTH0_ENABLED= AUTH0_CUSTOM_NAME= AUTH0_ISSUER= AUTH0_CLIENT_SECRET= AUTH0_CLIENT_ID= # Authelia NEXT_PUBLIC_AUTHELIA_ENABLED= AUTHELIA_CLIENT_ID= AUTHELIA_CLIENT_SECRET= AUTHELIA_WELLKNOWN_URL= # Authentik NEXT_PUBLIC_AUTHENTIK_ENABLED= AUTHENTIK_CUSTOM_NAME= AUTHENTIK_ISSUER= AUTHENTIK_CLIENT_ID= AUTHENTIK_CLIENT_SECRET= # Azure AD B2C NEXT_PUBLIC_AZURE_AD_B2C_ENABLED= AZURE_AD_B2C_TENANT_NAME= AZURE_AD_B2C_CLIENT_ID= AZURE_AD_B2C_CLIENT_SECRET= AZURE_AD_B2C_PRIMARY_USER_FLOW= # Azure AD NEXT_PUBLIC_AZURE_AD_ENABLED= AZURE_AD_CLIENT_ID= AZURE_AD_CLIENT_SECRET= AZURE_AD_TENANT_ID= # Battle.net NEXT_PUBLIC_BATTLENET_ENABLED= BATTLENET_CUSTOM_NAME= BATTLENET_CLIENT_ID= BATTLENET_CLIENT_SECRET= BATTLENET_ISSUER= # Box NEXT_PUBLIC_BOX_ENABLED= BOX_CUSTOM_NAME= BOX_CLIENT_ID= BOX_CLIENT_SECRET= # Bungie NEXT_PUBLIC_BUNGIE_ENABLED= BUNGIE_CUSTOM_NAME= BUNGIE_CLIENT_ID= BUNGIE_CLIENT_SECRET= BUNGIE_API_KEY= # Cognito NEXT_PUBLIC_COGNITO_ENABLED= COGNITO_CUSTOM_NAME= COGNITO_CLIENT_ID= COGNITO_CLIENT_SECRET= COGNITO_ISSUER= # Coinbase NEXT_PUBLIC_COINBASE_ENABLED= COINBASE_CUSTOM_NAME= COINBASE_CLIENT_ID= COINBASE_CLIENT_SECRET= # Discord NEXT_PUBLIC_DISCORD_ENABLED= DISCORD_CUSTOM_NAME= DISCORD_CLIENT_ID= DISCORD_CLIENT_SECRET= # Dropbox NEXT_PUBLIC_DROPBOX_ENABLED= DROPBOX_CUSTOM_NAME= DROPBOX_CLIENT_ID= DROPBOX_CLIENT_SECRET= # DuendeIndentityServer6 NEXT_PUBLIC_DUENDE_IDS6_ENABLED= DUENDE_IDS6_CUSTOM_NAME= DUENDE_IDS6_CLIENT_ID= DUENDE_IDS6_CLIENT_SECRET= DUENDE_IDS6_ISSUER= # EVE Online NEXT_PUBLIC_EVEONLINE_ENABLED= EVEONLINE_CUSTOM_NAME= EVEONLINE_CLIENT_ID= EVEONLINE_CLIENT_SECRET= # Facebook NEXT_PUBLIC_FACEBOOK_ENABLED= FACEBOOK_CUSTOM_NAME= FACEBOOK_CLIENT_ID= FACEBOOK_CLIENT_SECRET= # FACEIT NEXT_PUBLIC_FACEIT_ENABLED= FACEIT_CUSTOM_NAME= FACEIT_CLIENT_ID= FACEIT_CLIENT_SECRET= # Foursquare NEXT_PUBLIC_FOURSQUARE_ENABLED= FOURSQUARE_CUSTOM_NAME= FOURSQUARE_CLIENT_ID= FOURSQUARE_CLIENT_SECRET= FOURSQUARE_APIVERSION= # Freshbooks NEXT_PUBLIC_FRESHBOOKS_ENABLED= FRESHBOOKS_CUSTOM_NAME= FRESHBOOKS_CLIENT_ID= FRESHBOOKS_CLIENT_SECRET= # FusionAuth NEXT_PUBLIC_FUSIONAUTH_ENABLED= FUSIONAUTH_CUSTOM_NAME= FUSIONAUTH_CLIENT_ID= FUSIONAUTH_CLIENT_SECRET= FUSIONAUTH_ISSUER= FUSIONAUTH_TENANT_ID= # GitHub NEXT_PUBLIC_GITHUB_ENABLED= GITHUB_CUSTOM_NAME= GITHUB_ID= GITHUB_SECRET= # GitLab NEXT_PUBLIC_GITLAB_ENABLED= GITLAB_CUSTOM_NAME= GITLAB_CLIENT_ID= GITLAB_CLIENT_SECRET= GITLAB_AUTH_URL= # Google NEXT_PUBLIC_GOOGLE_ENABLED= GOOGLE_CUSTOM_NAME= GOOGLE_CLIENT_ID= GOOGLE_CLIENT_SECRET= # HubSpot NEXT_PUBLIC_HUBSPOT_ENABLED= HUBSPOT_CUSTOM_NAME= HUBSPOT_CLIENT_ID= HUBSPOT_CLIENT_SECRET= # IdentityServer4 NEXT_PUBLIC_IDS4_ENABLED= IDS4_CUSTOM_NAME= IDS4_CLIENT_ID= IDS4_CLIENT_SECRET= IDS4_ISSUER= # Kakao NEXT_PUBLIC_KAKAO_ENABLED= KAKAO_CUSTOM_NAME= KAKAO_CLIENT_ID= KAKAO_CLIENT_SECRET= # Keycloak NEXT_PUBLIC_KEYCLOAK_ENABLED= KEYCLOAK_CUSTOM_NAME= KEYCLOAK_ISSUER= KEYCLOAK_CLIENT_ID= KEYCLOAK_CLIENT_SECRET= # LINE NEXT_PUBLIC_LINE_ENABLED= LINE_CUSTOM_NAME= LINE_CLIENT_ID= LINE_CLIENT_SECRET= # LinkedIn NEXT_PUBLIC_LINKEDIN_ENABLED= LINKEDIN_CUSTOM_NAME= LINKEDIN_CLIENT_ID= LINKEDIN_CLIENT_SECRET= # Mailchimp NEXT_PUBLIC_MAILCHIMP_ENABLED= MAILCHIMP_CUSTOM_NAME= MAILCHIMP_CLIENT_ID= MAILCHIMP_CLIENT_SECRET= # Mail.ru NEXT_PUBLIC_MAILRU_ENABLED= MAILRU_CUSTOM_NAME= MAILRU_CLIENT_ID= MAILRU_CLIENT_SECRET= # Naver NEXT_PUBLIC_NAVER_ENABLED= NAVER_CUSTOM_NAME= NAVER_CLIENT_ID= NAVER_CLIENT_SECRET= # Netlify NEXT_PUBLIC_NETLIFY_ENABLED= NETLIFY_CUSTOM_NAME= NETLIFY_CLIENT_ID= NETLIFY_CLIENT_SECRET= # Okta NEXT_PUBLIC_OKTA_ENABLED= OKTA_CUSTOM_NAME= OKTA_CLIENT_ID= OKTA_CLIENT_SECRET= OKTA_ISSUER= # OneLogin NEXT_PUBLIC_ONELOGIN_ENABLED= ONELOGIN_CUSTOM_NAME= ONELOGIN_CLIENT_ID= ONELOGIN_CLIENT_SECRET= ONELOGIN_ISSUER= # Osso NEXT_PUBLIC_OSSO_ENABLED= OSSO_CUSTOM_NAME= OSSO_CLIENT_ID= OSSO_CLIENT_SECRET= OSSO_ISSUER= # osu! NEXT_PUBLIC_OSU_ENABLED= OSU_CUSTOM_NAME= OSU_CLIENT_ID= OSU_CLIENT_SECRET= # Patreon NEXT_PUBLIC_PATREON_ENABLED= PATREON_CUSTOM_NAME= PATREON_CLIENT_ID= PATREON_CLIENT_SECRET= # Pinterest NEXT_PUBLIC_PINTEREST_ENABLED= PINTEREST_CUSTOM_NAME= PINTEREST_CLIENT_ID= PINTEREST_CLIENT_SECRET= # Pipedrive NEXT_PUBLIC_PIPEDRIVE_ENABLED= PIPEDRIVE_CUSTOM_NAME= PIPEDRIVE_CLIENT_ID= PIPEDRIVE_CLIENT_SECRET= # Reddit NEXT_PUBLIC_REDDIT_ENABLED= REDDIT_CUSTOM_NAME= REDDIT_CLIENT_ID= REDDIT_CLIENT_SECRET= # Salesforce NEXT_PUBLIC_SALESFORCE_ENABLED= SALESFORCE_CUSTOM_NAME= SALESFORCE_CLIENT_ID= SALESFORCE_CLIENT_SECRET= # Slack NEXT_PUBLIC_SLACK_ENABLED= SLACK_CUSTOM_NAME= SLACK_CLIENT_ID= SLACK_CLIENT_SECRET= # Spotify NEXT_PUBLIC_SPOTIFY_ENABLED= SPOTIFY_CUSTOM_NAME= SPOTIFY_CLIENT_ID= SPOTIFY_CLIENT_SECRET= # Strava NEXT_PUBLIC_STRAVA_ENABLED= STRAVA_CUSTOM_NAME= STRAVA_CLIENT_ID= STRAVA_CLIENT_SECRET= # Synology NEXT_PUBLIC_SYNOLOGY_ENABLED= SYNOLOGY_CUSTOM_NAME= SYNOLOGY_CLIENT_ID= SYNOLOGY_CLIENT_SECRET= SYNOLOGY_WELLKNOWN_URL= # Todoist NEXT_PUBLIC_TODOIST_ENABLED= TODOIST_CUSTOM_NAME= TODOIST_CLIENT_ID= TODOIST_CLIENT_SECRET= # Twitch NEXT_PUBLIC_TWITCH_ENABLED= TWITCH_CUSTOM_NAME= TWITCH_CLIENT_ID= TWITCH_CLIENT_SECRET= # United Effects NEXT_PUBLIC_UNITED_EFFECTS_ENABLED= UNITED_EFFECTS_CUSTOM_NAME= UNITED_EFFECTS_CLIENT_ID= UNITED_EFFECTS_CLIENT_SECRET= UNITED_EFFECTS_ISSUER= # VK NEXT_PUBLIC_VK_ENABLED= VK_CUSTOM_NAME= VK_CLIENT_ID= VK_CLIENT_SECRET= # Wikimedia NEXT_PUBLIC_WIKIMEDIA_ENABLED= WIKIMEDIA_CUSTOM_NAME= WIKIMEDIA_CLIENT_ID= WIKIMEDIA_CLIENT_SECRET= # Wordpress.com NEXT_PUBLIC_WORDPRESS_ENABLED= WORDPRESS_CUSTOM_NAME= WORDPRESS_CLIENT_ID= WORDPRESS_CLIENT_SECRET= # Yandex NEXT_PUBLIC_YANDEX_ENABLED= YANDEX_CUSTOM_NAME= YANDEX_CLIENT_ID= YANDEX_CLIENT_SECRET= # Zitadel NEXT_PUBLIC_ZITADEL_ENABLED= ZITADEL_CUSTOM_NAME= ZITADEL_CLIENT_ID= ZITADEL_CLIENT_SECRET= ZITADEL_ISSUER= # Zoho NEXT_PUBLIC_ZOHO_ENABLED= ZOHO_CUSTOM_NAME= ZOHO_CLIENT_ID= ZOHO_CLIENT_SECRET= # Zoom NEXT_PUBLIC_ZOOM_ENABLED= ZOOM_CUSTOM_NAME= ZOOM_CLIENT_ID= ZOOM_CLIENT_SECRET= # Generic OIDC NEXT_PUBLIC_OIDC_ENABLED= OIDC_CUSTOM_NAME= OIDC_WELLKNOWN_URL= OIDC_CLIENT_ID= OIDC_CLIENT_SECRET= OIDC_SCOPES= - What the compose file check ran with (github.com/linkwarden/docs/blob/53e2dce/docs/self-hosting/setup.md)
The compose file check ran together with .env.sample from the same commit, saved as .env. The folder held only these files. The self-hosting guide tells the reader to download docker-compose.yml and .env.sample (saved as .env), change the secrets and run docker compose up.
- Start it (github.com/linkwarden/docs/blob/53e2dce/docs/self-hosting/setup.md)
docker compose up -d - Open the app (github.com/linkwarden/linkwarden/blob/952ac45/docker-compose.yml)
Open http://localhost:3000. The compose file publishes host port 3000 for the linkwarden service.
Compose file check: config_ok on 2026-10-22.
Gotchas and maintenance
Gotchas
- Some images use the latest tag or no tag. Images without a pinned version: linkwarden: ghcr.io/linkwarden/linkwarden:latest. A later pull can get a different version. (github.com/linkwarden/linkwarden/blob/952ac45/docker-compose.yml, checked 2026-10-22)
- The compose file publishes host ports. Host ports: 3000 (linkwarden). A port without a host address listens on all host network interfaces. (github.com/linkwarden/linkwarden/blob/952ac45/docker-compose.yml, checked 2026-10-22)
- The compose file mounts host folders. Host paths mounted into containers: ./pgdata at /var/lib/postgresql/data (postgres), ./data at /data/data (linkwarden), ./meili_data at /meili_data (meilisearch). (github.com/linkwarden/linkwarden/blob/952ac45/docker-compose.yml, checked 2026-10-22)
Signals
- Open issues and pull requests: 688
- Last push: 2026-10-19 (3 days before this page was built)
- Latest release: v2.16.3 on 2026-09-09 (43 days before this page was built)