Skip to content

Telegram Mini App for One Million Users: How We Built a Scalable Gaming Platform with Django

By Yurii Yarmola, Backend Developer / / 7 min read

Telegram Mini App for One Million Users: How We Built a Scalable Gaming Platform with Django

Telegram Mini Apps have evolved far beyond simple web applications running inside a messenger. Today, they can be full-fledged products featuring gaming mechanics, personalized content, complex business logic, and hundreds of thousands of potential users.

In one of our projects, we developed exactly this kind of application for a large Telegram channel. The Mini App combined gaming features with a dedicated news section that mirrored content from the main channel.

The main challenge wasn't just implementing the functionality. We needed to build a backend capable of serving users reliably, handling sudden traffic spikes, and providing room for future growth — potentially supporting an audience of one million users.

In this article, we'll explore the main engineering challenges we faced, the architectural decisions we made, and the approaches that helped us bring the project to stable production operation.

1. The Challenge of Telegram Mini Apps: Traffic Comes in Waves

Unlike traditional web applications, where traffic can be relatively predictable, Telegram Mini Apps may experience sudden spikes in activity.

For example, after a new post is published in a Telegram channel, thousands of subscribers may open the application within a short period.

However, each Mini App launch involves more than a single HTTP request. Users need to authenticate, load their profiles, retrieve game data, browse news, and interact with various application features.

To understand the potential scale, let's consider a hypothetical scenario:

  • Channel audience: 1,000,000 subscribers.
  • 1% of the audience opens the application within 5 minutes.
  • That's 10,000 application launches in a short period.
  • If each launch generates an average of 5 API requests, the system receives 50,000 requests — approximately 167 RPS (requests per second) on average.

These figures illustrate a potential load scenario rather than the application's actual production metrics. Real traffic patterns can be significantly less predictable, with peak RPS potentially exceeding the average.

This is why we paid particular attention to backend architecture, database performance, and load testing from the early stages of development.

2. Architecture: Django, PostgreSQL, Redis, and Celery

We chose Django as the foundation of our backend. PostgreSQL handled persistent data storage, Redis served as a high-speed in-memory infrastructure component, and Celery enabled background task processing.

This technology stack allowed us to separate responsibilities across the system's main components.

Django handled API endpoints, business logic, user interactions, and gaming mechanics. PostgreSQL provided reliable data persistence, Redis supported operations requiring fast access to in-memory data, and Celery allowed time-consuming tasks to be processed outside the HTTP request-response cycle.

One important architectural consideration was that gaming functionality and news content had different workload characteristics.

The news section was primarily read-heavy. Thousands of users could potentially request the same article simultaneously. Gaming functionality, on the other hand, involved personalized data and operations that modified user state.

This distinction matters because caching strategies that work well for public content are not always appropriate for operations involving game progress, balances, or other user-specific data.

Understanding these differences helped us approach performance optimization more systematically.

3. PostgreSQL Optimization: When One API Request Generates Dozens of SQL Queries

One of the main engineering challenges during development was optimizing database interactions.

Django ORM makes working with PostgreSQL significantly easier. However, even a relatively simple piece of application code can unintentionally generate a large number of SQL queries.

A classic example is the N+1 query problem.

Imagine an API endpoint that returns a list of game objects along with their related data. If each object triggers an additional database query, the total number of queries grows with the size of the result set.

Django provides tools such as select_related() and prefetch_related() to efficiently retrieve related data and reduce unnecessary database operations.

However, database optimization goes beyond ORM configuration.

It is also important to analyze SQL execution plans, database indexes, query patterns, connection usage, and the operations performed most frequently.

Throughout the project, query optimization was one of our key development priorities.

The main lesson was simple: prioritize operations whose cost increases with the number of active users.

An unnecessary database query may be insignificant with ten users, but it can become a substantial source of overhead when thousands of requests are processed concurrently.

4. Redis and Celery: Separating Fast Responses from Background Processing

Another important aspect of performance optimization is avoiding unnecessary work within synchronous HTTP requests.

Applications that combine gaming mechanics and content distribution often have two categories of operations: those requiring an immediate response and those that can be processed asynchronously.

Redis and Celery provide useful building blocks for separating these workloads.

Redis is well suited for scenarios requiring fast data access, such as caching frequently requested content or maintaining auxiliary application state.

Celery enables time-consuming operations to be delegated to background workers instead of blocking API responses.

However, introducing these components also creates additional engineering considerations:

  • Cache expiration and invalidation strategies.
  • Reliable background task execution.
  • Idempotency and duplicate processing prevention.
  • Error handling and retry mechanisms.
  • System behavior when individual components become temporarily unavailable.

These considerations are especially important for gaming applications.

For example, a repeated API request or a retried background task must not accidentally update a user's balance or game progress multiple times.

The goal is not simply to move operations into background workers, but to make application behavior reliable and predictable under varying workloads.

5. API Security: A Telegram User ID Is Not Proof of Authentication

API security was another important area of our development work.

One characteristic of Telegram Mini Apps is that user information reaches the backend through the frontend. However, any information received from a client must be treated as potentially untrusted.

The backend should never assume that a provided user_id belongs to the actual user simply because it matches the expected Telegram ID format.

Telegram provides a mechanism called initData, which contains user information and can be cryptographically verified by the backend.

For the standard bot-token-based validation flow, this involves HMAC-SHA-256 verification.

In addition to validating the integrity of the data, the backend should verify its freshness using auth_date and ensure that users cannot perform operations on behalf of other accounts.

This is particularly important in gaming applications.

For example, the frontend may send a request indicating that a player has performed a certain action. However, the backend must independently verify whether that action is allowed and determine how it affects the application's state.

The client may initiate an action, but it should never have the authority to determine its outcome.

This principle helps reduce the risk of API parameter manipulation, unauthorized access, and exploitation of gaming mechanics.

6. Load Testing: Testing the Entire System, Not Just Individual Endpoints

Load testing became another significant part of our development process.

An API may perform perfectly well during regular development and testing, but that does not guarantee stability when thousands of requests arrive concurrently.

Load testing allows engineers to evaluate system behavior under conditions resembling potential production traffic spikes.

For a Telegram Mini App, it is particularly useful to simulate complete user journeys rather than testing individual endpoints in isolation.

A typical scenario might include opening the application, authenticating, loading initial data, retrieving news, and interacting with gaming functionality.

Several metrics are especially useful when evaluating the results:

  • RPS (Requests Per Second): The number of requests processed each second.
  • p95/p99 latency: Response-time percentiles representing the slowest 5% and 1% of requests.
  • Error rate: The percentage of requests that fail.
  • CPU and RAM usage: Resource consumption under load.
  • Database connections: The number of active PostgreSQL connections.

It is also important to understand that increasing the number of backend processes does not automatically solve performance problems.

If PostgreSQL is already the system's bottleneck, adding more application workers may simply increase the number of simultaneous database connections and make the situation worse.

Load testing therefore serves two purposes: evaluating overall performance and identifying which components actually need optimization.

In our project, these tests played an important role in preparing the application for stable production operation.

7. DevOps Architecture: Scalability Is More Than Fast Code

Even a well-optimized backend can become unreliable if the infrastructure is not designed for its workload.

That is why developing the DevOps architecture was another major part of the project.

We needed to approach the infrastructure as an integrated system, ensuring that Django, PostgreSQL, Redis, Celery, and the deployment processes could operate together reliably.

An important consideration in this type of architecture is separating API processes from background workers.

This makes it possible to manage their resources independently and prevents background processing from directly competing with API requests for the same application worker capacity.

Horizontal scaling also introduces its own requirements.

Ideally, individual API instances should not depend on process-local user state. This allows additional instances to be introduced without disrupting active users or application behavior.

However, scaling application instances must always be considered alongside the limitations of shared infrastructure.

For example, increasing the number of Django workers can also increase the number of PostgreSQL connections, potentially creating new performance problems.

This leads to an important principle:

Scalability must be designed at the system level, not independently for each service.

A reliable infrastructure should support predictable deployment, efficient resource allocation, recovery from failures, and gradual expansion as demand increases.

8. Results and Lessons Learned

Ultimately, we successfully completed the project and brought the Telegram Mini App into stable operation.

We delivered a gaming application with integrated news functionality using Django, PostgreSQL, Redis, and Celery.

Throughout development, we addressed challenges related to database query optimization, API security, load testing, and infrastructure architecture.

The most important lesson from this experience was that preparing an application for a large audience starts with understanding how the system behaves, rather than immediately introducing complex infrastructure.

Based on this project, we would highlight three principles:

1. Measure before scaling.

A popular application does not necessarily require more servers. First, identify actual bottlenecks through profiling, monitoring, and load testing.

2. Separate responsibilities across components.

Django, PostgreSQL, Redis, and Celery should each handle the workloads they are best suited for, without introducing unnecessary dependencies.

3. Design for traffic spikes, not just average traffic.

Telegram channels can generate large waves of user activity within short periods. Backend and infrastructure decisions should account for this behavior.

This project demonstrated that an application targeting a potentially million-strong audience does not necessarily require a complex microservices architecture from day one.

A well-designed Django backend, optimized database interactions, carefully implemented security, and properly tested infrastructure can provide a solid foundation for a product that grows alongside its audience.

YOUR NEXT PRODUCT
STARTS HERE.

From idea to launch — we're ready when you are.

Start a Project

[Blog] Keep reading

Jamal Aha

Jamal Aha

CEO, Techchain

YOUR NEXT PRODUCT
STARTS HERE

What services we can
support you with?