selfhostedworld.com logoselfhostedworld.com

Try describing what you need:

HyperSwitch logo

HyperSwitch

★ 45.3k

A self-hosted alternative to Stripe

Apache License 2.0Open Source — No Paywall30 Containers — 30 containers — heavy hosting footprintDocker · HelmNeeds Postgres16 documented maintainers

About

Hyperswitch is an open-source payments infrastructure project aimed at businesses and engineering teams that want more control over their payment stack. It is designed to be modular, letting users...

Community Ratings

No ratings yet
Quickstart demo

Features

  • modular payments infrastructure
  • cost observability
  • revenue recovery
  • PCI-compliant vault
  • intelligent routing
  • reconciliation
  • alternate payment methods
  • visual workflow builder
  • hosted sandbox
  • multi-PSP connector support

Details

Last Updated
Oct 18, 2026
Created
Oct 17, 2022
Install Methods
dockerhelm
Requirements
Docker/Podman
Runtime / Stack
DockerRust
Privacy & Independence
Cloud: Optional
User Model
Multi-User
Deployment

Deployment: Docker Compose ✓30 Containers — heavy hosting footprintRuns as 30 containers

Run HyperSwitch with Docker Compose

Compose file from the HyperSwitch project repository.

30 services · database: postgres · infra: postgres, redis, opensearch · 22 unclassified (curl-base, debian, alpine, mailhog, hyperswitch-router, hyperswitch-producer, hyperswitch-consumer, hyperswitch-drainer, hyperswitch-web, hyperswitch-control-center, grafana, loki, opentelemetry-collector-contrib, prometheus, tempo, redisinsight, cp-kafka, kafka-ui, clickhouse-server, opensearch-dashboards, vector, hyperswitch-react-demo-app)

no resource limits declared

needs persistent storage (26 volumes)

docker-compose.yml · @ 08eef46 · scanned Sep 25, 2026

volumes:
  pg_data:
  redisinsight_store:
  ckh_data:

networks:
  router_net:

services:
  ### Dependencies
  prestart-hook:
    image: docker.io/curlimages/curl-base:latest
    container_name: prestart-hook
    environment:
      - ONE_CLICK_SETUP=${ONE_CLICK_SETUP:-false}
    entrypoint:
      [
        "/bin/sh",
        "-c",
        "apk add --no-cache bash && /bin/bash /prestart_hook.sh",
      ]
    volumes:
      - ./scripts/prestart_hook.sh:/prestart_hook.sh
    networks:
      - router_net

  pg:
    image: docker.io/postgres:latest
    ports:
      - "5432:5432"
    networks:
      - router_net
    volumes:
      - pg_data:/var/lib/postgresql
    environment:
      - POSTGRES_USER=db_user
      - POSTGRES_PASSWORD=db_pass
      - POSTGRES_DB=hyperswitch_db
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
      interval: 5s
      retries: 3
      start_period: 5s
      timeout: 5s

  redis-standalone:
    image: docker.io/redis:7
    networks:
      - router_net
    ports:
      - "6379:6379"
    healthcheck:
      test: ["CMD-SHELL", "redis-cli ping | grep '^PONG$'"]
      interval: 5s
      retries: 3
      start_period: 5s
      timeout: 5s

  migration_runner:
    image: docker.io/debian:trixie-slim
    pull_policy: always
    command: >
      bash -c "
      apt-get update && apt-get install -y curl xz-utils &&
      curl --proto '=https' --tlsv1.2 -LsSf https://github.com/diesel-rs/diesel/releases/download/v2.3.5/diesel_cli-installer.sh | bash &&
      if ! command -v just >/dev/null 2>&1; then
        curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin
      fi &&
      export PATH="$${PATH}:$${HOME}/.cargo/bin" &&
      just migrate"
    working_dir: /app
    networks:
      - router_net
    volumes:
      - ./:/app
    environment:
      # format -> postgresql://DB_USER:DB_PASSWORD@HOST:PORT/DATABASE_NAME
      - DATABASE_URL=postgresql://db_user:db_pass@pg:5432/hyperswitch_db

  superposition:
    image: ghcr.io/juspay/superposition-demo:0.113.0
    ports:
      - "8081:8080"
    networks:
      - router_net
    environment:
      - API_HOSTNAME=http://localhost:8081
      - REDIS_URL=redis://redis-standalone:6379
    depends_on:
      redis-standalone:
        condition: service_healthy

  superposition-init:
    image: alpine:latest
    depends_on:
      superposition:
        condition: service_started
    networks:
      - router_net
    volumes:
      - ./config/superposition_seed.toml:/seed.toml:ro
      - ./scripts/seed_superposition.sh:/seed_superposition.sh:ro
    environment:
      - SUPERPOSITION_URL=http://superposition:8080
      - SEED_FILE=/seed.toml
      - WORKSPACE_ID=dev
      - ORG_ID=localorg
    command: sh -c "apk add --no-cache curl jq yq && sh /seed_superposition.sh"
    restart: "no"

  mailhog:
    image: docker.io/mailhog/mailhog
    networks:
      - router_net
    profiles:
      - full_setup
    ports:
      - "1025:1025"
      - "8025:8025"

  ### Application services
  hyperswitch-server:
    image: docker.juspay.io/juspaydotin/hyperswitch-router:standalone
    pull_policy: always
    command: /local/bin/router -f /local/config/docker_compose.toml
    ports:
      - "8080:8080"
    networks:
      - router_net
    volumes:
      - ./config:/local/config
      - ./files:/local/bin/files
    depends_on:
      pg:
        condition: service_healthy
      redis-standalone:
        condition: service_healthy
      migration_runner:
        condition: service_completed_successfully
      superposition-init:
        condition: service_completed_successfully
    labels:
      logs: "promtail"
    healthcheck:
      test: curl --fail http://localhost:8080/health || exit 1
      interval: 5s
      retries: 3
      start_period: 5s
      timeout: 5s

  hyperswitch-producer:
    image: docker.juspay.io/juspaydotin/hyperswitch-producer:standalone
    pull_policy: always
    command: /local/bin/scheduler -f /local/config/docker_compose.toml
    networks:
      - router_net
    profiles:
      - scheduler
    volumes:
      - ./config:/local/config
    environment:
      - SCHEDULER_FLOW=producer
    depends_on:
      hyperswitch-consumer:
        condition: service_healthy
    labels:
      logs: "promtail"

  hyperswitch-consumer:
    image: docker.juspay.io/juspaydotin/hyperswitch-consumer:standalone
    pull_policy: always
    command: /local/bin/scheduler -f /local/config/docker_compose.toml
    networks:
      - router_net
    profiles:
      - scheduler
    volumes:
      - ./config:/local/config
    environment:
      - SCHEDULER_FLOW=consumer
    depends_on:
      hyperswitch-server:
        condition: service_healthy
    labels:
      logs: "promtail"
    healthcheck:
      test: (ps -e | grep scheduler) || exit 1
      interval: 10s
      retries: 3
      start_period: 5s
      timeout: 10s

  hyperswitch-drainer:
    image: docker.juspay.io/juspaydotin/hyperswitch-drainer:standalone
    pull_policy: always
    command: /local/bin/drainer -f /local/config/docker_compose.toml
    deploy:
      replicas: ${DRAINER_INSTANCE_COUNT:-1}
    networks:
      - router_net
    profiles:
      - full_kv
    volumes:
      - ./config:/local/config
    restart: unless-stopped
    depends_on:
      hyperswitch-server:
        condition: service_healthy
    labels:
      logs: "promtail"

  ### Web Client
  hyperswitch-web:
    image: docker.juspay.io/juspaydotin/hyperswitch-web:latest
    pull_policy: always
    ports:
      - "9050:9050"
    networks:
      - router_net
    depends_on:
      hyperswitch-server:
        condition: service_healthy
    environment:
      - ENABLE_LOGGING=true
      - SDK_ENV=local
      - ENV_LOGGING_URL=http://localhost:3103
      - ENV_BACKEND_URL=http://localhost:8080
    labels:
      logs: "promtail"

  ### Control Center
  hyperswitch-control-center:
    image: docker.juspay.io/juspaydotin/hyperswitch-control-center:latest
    pull_policy: always
    ports:
      - "9000:9000"
    environment:
      - configPath=/tmp/dashboard-config.toml
      - themeConfigPath=/tmp/dashboard-theme.json
    volumes:
      - ./config/dashboard.toml:/tmp/dashboard-config.toml
      - ./config/dashboard_theme.json:/tmp/dashboard-theme.json
    depends_on:
      hyperswitch-server:
        condition: service_healthy
      hyperswitch-web:
        condition: service_started
    labels:
      logs: "promtail"

  create-default-user:
    image: docker.io/curlimages/curl-base:latest
    container_name: create-default-user
    depends_on:
      hyperswitch-server:
        condition: service_healthy
      hyperswitch-control-center:
        condition: service_started
    environment:
      - HYPERSWITCH_SERVER_URL=http://hyperswitch-server:8080
      - HYPERSWITCH_CONTROL_CENTER_URL=http://hyperswitch-control-center:9000
    entrypoint:
      [
        "/bin/sh",
        "-c",
        "apk add --no-cache bash jq && /bin/bash /create_default_user.sh",
      ]
    volumes:
      - ./scripts/create_default_user.sh:/create_default_user.sh
    networks:
      - router_net

  poststart-hook:
    image: docker.io/curlimages/curl-base:latest
    container_name: poststart-hook
    depends_on:
      hyperswitch-server:
        condition: service_healthy # Ensures it only starts when `hyperswitch-server` is healthy
    environment:
      - ONE_CLICK_SETUP=${ONE_CLICK_SETUP:-false}
    entrypoint:
      [
        "/bin/sh",
        "-c",
        "apk add --no-cache bash jq && /bin/bash /poststart_hook.sh",
      ]
    volumes:
      - ./scripts/poststart_hook.sh:/poststart_hook.sh
    networks:
      - router_net

  ### Clustered Redis setup
  redis-cluster:
    image: docker.io/redis:7
    deploy:
      replicas: ${REDIS_CLUSTER_COUNT:-3}
    command: redis-server /usr/local/etc/redis/redis.conf
    profiles:
      - clustered_redis
    volumes:
      - ./config/redis.conf:/usr/local/etc/redis/redis.conf
    networks:
      - router_net
    ports:
      - "6379"
      - "16379"

  redis-init:
    image: docker.io/redis:7
    profiles:
      - clustered_redis
    depends_on:
      - redis-cluster
    networks:
      - router_net
    command: |-
      bash -c 'export COUNT=${REDIS_CLUSTER_COUNT:-3}
      if [ $$COUNT -lt 3 ]
      then
      echo \"Minimum 3 nodes are needed for redis cluster\"
      exit 1
      fi
      HOSTS=\"\"
      for ((c=1; c<=$$COUNT;c++))
      do
      NODE=$COMPOSE_PROJECT_NAME-redis-cluster-$$c:6379
      echo $$NODE
      HOSTS=\"$$HOSTS $$NODE\"
      done
      echo Creating a cluster with $$HOSTS
      redis-cli --cluster create $$HOSTS --cluster-yes
      '
  ### Monitoring
  grafana:
    image: docker.io/grafana/grafana:latest
    ports:
      - "3000:3000"
    networks:
      - router_net
    profiles:
      - monitoring
    restart: unless-stopped
    environment:
      - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
      - GF_AUTH_ANONYMOUS_ENABLED=true
      - GF_AUTH_BASIC_ENABLED=false
    volumes:
      - ./config/grafana.ini:/etc/grafana/grafana.ini
      - ./config/grafana-datasource.yaml:/etc/grafana/provisioning/datasources/datasource.yml

  loki:
    image: docker.io/grafana/loki:latest
    ports:
      - "3100"
    command: -config.file=/etc/loki/loki.yaml
    networks:
      - router_net
    profiles:
      - monitoring
    volumes:
      - ./config:/etc/loki

  otel-collector:
    image: docker.io/otel/opentelemetry-collector-contrib:latest
    command: --config=/etc/otel-collector.yaml
    networks:
      - router_net
    profiles:
      - monitoring
    volumes:
      - ./config/otel-collector.yaml:/etc/otel-collector.yaml
    ports:
      - "4317"
      - "8888"
      - "8889"

  prometheus:
    image: docker.io/prom/prometheus:latest
    networks:
      - router_net
    profiles:
      - monitoring
    volumes:
      - ./config/prometheus.yaml:/etc/prometheus/prometheus.yml
    ports:
      - "9090"
    restart: unless-stopped

  tempo:
    image: docker.io/grafana/tempo:latest
    command: -config.file=/etc/tempo.yaml
    volumes:
      - ./config/tempo.yaml:/etc/tempo.yaml
    networks:
      - router_net
    profiles:
      - monitoring
    ports:
      - "3200" # tempo
      - "4317" # otlp grpc
    restart: unless-stopped

  redis-insight:
    image: docker.io/redislabs/redisinsight:latest
    networks:
      - router_net
    profiles:
      - monitoring
    ports:
      - "8001:8001"
    volumes:
      - redisinsight_store:/db

  kafka0:
    image: docker.io/confluentinc/cp-kafka:7.0.5
    hostname: kafka0
    networks:
      - router_net
    ports:
      - 9092:9092
      - 9093
      - 9997
      - 29092
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka0:29092,PLAINTEXT_HOST://localhost:9092
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
      KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
      KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
      KAFKA_PROCESS_ROLES: "broker,controller"
      KAFKA_NODE_ID: 1
      KAFKA_CONTROLLER_QUORUM_VOTERS: "1@kafka0:29093"
      KAFKA_LISTENERS: "PLAINTEXT://kafka0:29092,CONTROLLER://kafka0:29093,PLAINTEXT_HOST://0.0.0.0:9092"
      KAFKA_CONTROLLER_LISTENER_NAMES: "CONTROLLER"
      KAFKA_LOG_DIRS: "/tmp/kraft-combined-logs"
      JMX_PORT: 9997
      KAFKA_JMX_OPTS: -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=kafka0 -Dcom.sun.management.jmxremote.rmi.port=9997
    profiles:
      - olap
    volumes:
      - ./monitoring/kafka-script.sh:/tmp/update_run.sh
    command: 'bash -c ''if [ ! -f /tmp/update_run.sh ]; then echo "ERROR: Did you forget the update_run.sh file that came with this docker-compose.yml file?" && exit 1 ; else /tmp/update_run.sh && /etc/confluent/docker/run ; fi'''

  # Kafka UI for debugging kafka queues
  kafka-ui:
    image: docker.io/provectuslabs/kafka-ui:latest
    ports:
      - 8090:8080
    networks:
      - router_net
    depends_on:
      - kafka0
    profiles:
      - olap
    environment:
      KAFKA_CLUSTERS_0_NAME: local
      KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka0:29092
      KAFKA_CLUSTERS_0_JMXPORT: 9997

  clickhouse-server:
    image: docker.io/clickhouse/clickhouse-server:24.3
    networks:
      - router_net
    ports:
      - "9000"
      - "8123:8123"
    volumes:
      - ./crates/analytics/docs/clickhouse/scripts:/docker-entrypoint-initdb.d
    environment:
      - TZ=Asia/Kolkata
    profiles:
      - olap
    ulimits:
      nofile:
        soft: 262144
        hard: 262144

  opensearch:
    image: docker.io/opensearchproject/opensearch:2
    container_name: opensearch
    hostname: opensearch
    environment:
      - "discovery.type=single-node"
      - OPENSEARCH_INITIAL_ADMIN_PASSWORD=0penS3arc#
      - LOG_LEVEL=DEBUG
    profiles:
      - olap
    ports:
      - "9200:9200"
    networks:
      - router_net

  opensearch-dashboards:
    image: docker.io/opensearchproject/opensearch-dashboards:2
    ports:
      - 5601:5601
    profiles:
      - olap
    environment:
      OPENSEARCH_HOSTS: '["https://opensearch:9200"]'
    networks:
      - router_net

  vector:
    image: docker.io/timberio/vector:latest-debian
    ports:
      - "8686"
      - "9598"
      - "3103:3103"
    profiles:
      - olap
    environment:
      KAFKA_HOST: "kafka0:29092"
    networks:
      - router_net
    volumes:
      - ./config/vector.yaml:/etc/vector/vector.yaml
      - /var/run/docker.sock:/var/run/docker.sock

  hyperswitch-demo:
    image: docker.juspay.io/juspaydotin/hyperswitch-react-demo-app:latest
    pull_policy: always
    ports:
      - "9060:9060"
      - "5252:5252"
    networks:
      - router_net
    profiles:
      - full_setup
    depends_on:
      hyperswitch-server:
        condition: service_healthy
      hyperswitch-web:
        condition: service_started
    environment:
      - HYPERSWITCH_PUBLISHABLE_KEY=placeholder_publishable_key
      - HYPERSWITCH_SECRET_KEY=placeholder_api_key
      - PROFILE_ID=placeholder_profile_id
      - HYPERSWITCH_CLIENT_URL=http://localhost:9050
      - HYPERSWITCH_SERVER_URL=http://localhost:8080
    labels:
      logs: "promtail"

This file may be out of date. Check the HyperSwitch documentation for current setup steps.

Track your self-hosted stack

Bookmark software to try, rate tools you've used, and keep your collection in one place.

Metadata extracted from README on Jul 8, 2026

Related Software

BTCPay Server logo

BTCPay Server

7.8k
BTCPay Server is a free, open-source Bitcoin payment processor for accepting Bitcoin payments without fees or intermediaries.
Budgeting and FinancePermissive LicenseE-Commerce Solutions+2
12 ContainersFully FOSS
Details
Kill Bill logo

Kill Bill

5.8k
An open-source subscription billing and payments platform for SaaS and other online businesses.
Budgeting and FinanceE-Commerce SolutionsAnalytics Tools+2
Details
SHKeeper logo

SHKeeper

635
SHKeeper is an open-source, self-hosted cryptocurrency payment processor for accepting direct payments in multiple cryptocurrencies.
Budgeting and FinanceCopyleft LicenseE-Commerce Solutions+1
Details
FOSSBilling logo

FOSSBilling

1.7k
A free, open-source billing and client management system for automating invoicing, payments, and client communication.
Budgeting and FinancePermissive LicenseE-Commerce Solutions+3
Details
Bitcart logo

Bitcart

991
Bitcart is a platform for merchants, users, and developers that aims to provide easy setup and use.
Budgeting and FinancePermissive LicenseE-Commerce Solutions+1
Details
DePay logo

DePay

135
A crypto web3 payment widget for accepting wallet-to-wallet payments across supported blockchains.
Budgeting and FinanceE-Commerce SolutionsSelf Hosting Solutions+1
Details
Spree Commerce logo

Spree Commerce

15.8k
An open-source headless eCommerce platform with a REST API, TypeScript SDK, admin dashboard, CLI, and Next.js storefront.
E-Commerce SolutionsInventory ManagementAPI Management+2
Details
Sylius logo

Sylius

8.6k
Sylius is an open source eCommerce framework built on Symfony for creating tailored online shopping applications.
E-Commerce SolutionsInventory ManagementAPI Management+1
Details
MedusaJs logo

MedusaJs

36.8k
Medusa is a commerce platform and customization framework for building custom digital commerce applications.
E-Commerce SolutionsPermissive LicenseInventory Management+1
Details
Shopware Community Edition logo

Shopware Community Edition

3.5k
Shopware is an open source e-commerce platform and framework for building shopping cart and headless commerce experiences.
E-Commerce SolutionsPermissive LicenseCMS Platforms+2
Details
Vendure logo

Vendure

8.5k
Vendure Core is the open source foundation of Vendure, an enterprise commerce platform for building scalable digital commerce applications.
E-Commerce SolutionsInventory ManagementAPI Management+1
Open Core
Details
Bagisto logo

Bagisto

28.2k
Bagisto is an open-source Laravel eCommerce framework for building online stores and marketplaces.
E-Commerce SolutionsPermissive LicenseInventory Management
6 Containers
Details