Developing a High-Load Fitness Club Website on 1С-Bitrix
A client visits your fitness club website on Monday evening, picks a class, clicks "Book Now" — and sees "Server Error." Or the schedule takes 5 seconds to load. The architecture isn't designed for peak loads. We're a team of certified 1С-Bitrix engineers with 8+ years of experience, solving these problems turnkey. We design high-load structures, configure caching, integrate with payment systems and CRM. We guarantee 99.9% uptime during peak hours. Let's assess your project within 2 days with a free audit.
Problems We Solve
Typical scenario: a weekly schedule with 300 classes, 15 halls, 40 trainers. Without proper optimization, filtering takes 800–1200 ms. We transfer data to Highload blocks — flat tables with indexes. Filtering time drops to 20–30 ms — a 45x improvement compared to standard infoblocks. Below we break down the key nodes of such a project.
How We Design the Schedule for High Load
The schedule is the central element of the site. If it's slow, the client switches to a competitor's Telegram bot.
For storing the schedule, we use HL blocks. A regular infoblock (EAV model) with 300 classes, 15 halls, and 40 trainers produces tens of thousands of rows in the property table. Filtering by a combination of "hall + day + trainer + direction" results in a series of JOINs taking 800–1200 ms.
A Highload block is a flat MySQL table. One row = one class, all fields are columns. Filtering uses regular indexes.
Structure of HL FitnessSchedule:
| Field | Type | Purpose |
|---|---|---|
| UF_DATE | date | Date of class |
| UF_TIME_START | string | Start (HH:MM) |
| UF_TIME_END | string | End |
| UF_HALL_ID | integer | Hall ID (link to HL FitnessHalls) |
| UF_TRAINER_ID | integer | Trainer ID |
| UF_DIRECTION_ID | integer | Direction: yoga, crossfit, pool... |
| UF_CAPACITY | integer | Maximum participants |
| UF_BOOKED | integer | Current booked count |
| UF_STATUS | enumeration | active / cancelled / full |
| UF_IS_RECURRING | boolean | Recurring by template |
| UF_TEMPLATE_ID | integer | Link to schedule template |
For recurring classes, we use a separate HL ScheduleTemplate. A cron agent generates specific classes once a week. This allows a trainer to cancel a specific class without breaking the entire schedule.
Front-end filtering via DataManager::getList():
$result = $entityClass::getList([
'filter' => [
'UF_DATE' => $selectedDate,
'UF_HALL_ID' => $hallId,
'UF_STATUS' => 'active',
],
'order' => ['UF_TIME_START' => 'ASC'],
]);
On the front end, we use a grid: halls on the horizontal axis, time slots on the vertical. AJAX requests through a custom REST endpoint.
Why Highload Blocks Outperform Infoblocks
With 50,000 records, an HL block processes a filter in 20 ms, while an infoblock takes 900 ms — a 45x difference. This is due to the absence of EAV layers and the use of direct indexes. HL blocks support SELECT ... FOR UPDATE, critical for transactional writes. This architecture is 3x more efficient than using standard infoblocks for concurrent bookings.
Online Booking with Capacity Limits and Waitlist
Booking a class is a transactional operation that checks limits, handles concurrent access, and provides a waitlist mechanism.
Scenario:
- Client clicks "Book Now"
- System checks:
UF_BOOKED < UF_CAPACITY - If yes — creates a record in HL
FitnessBooking, incrementsUF_BOOKED - If no — offers to join the waitlist
Concurrent access is resolved using a transaction with row locking. Two clients clicking simultaneously on a class with one remaining spot would both get confirmation without locking.
Solution — raw SQL with SELECT ... FOR UPDATE:
$connection = \Bitrix\Main\Application::getConnection();
$connection->startTransaction();
$row = $entityClass::getList([
'filter' => ['ID' => $scheduleId],
'select' => ['UF_BOOKED', 'UF_CAPACITY'],
// FOR UPDATE via raw SQL
])->fetch();
if ($row['UF_BOOKED'] < $row['UF_CAPACITY']) {
// create booking
$connection->commitTransaction();
} else {
$connection->rollbackTransaction();
// offer waitlist
}
The Bitrix ORM does not support SELECT ... FOR UPDATE, so we wrap the critical section in raw SQL.
The waitlist is implemented via a separate HL FitnessWaitlist. When someone cancels a booking, an agent checks the waitlist and moves the first person in line, sending an SMS/push. This reduces no-shows by 30%.
Cancellation: the club allows cancellation 2–4 hours before the start. The logic in the event handler compares the cancellation time.
Selling Memberships via the Sale Module
Memberships are not simple products. They have a validity period, visit limit, and freeze capability.
Membership types are implemented as infoblock elements with properties:
-
DURATION_DAYS,VISIT_LIMIT,TYPE,FREEZE_ALLOWED,FREEZE_MAX_DAYS
On purchase via Order::create(), the membership is added to the cart. After payment, the OnSaleOrderPaid handler creates a record in HL UserSubscription with fields: UF_USER_ID, UF_START_DATE, UF_END_DATE, UF_VISITS_LEFT, UF_IS_FROZEN, UF_FREEZE_START.
Freeze: the client clicks "Freeze," the system checks limits and sets UF_IS_FROZEN. On unfreeze, it recalculates UF_END_DATE.
Integration with Club CRM Systems
Fitness clubs use 1С:Fitness Club or Mobifitness.
1С:Fitness Club — exchange via CommerceML or REST API. We synchronize services, schedules, clients, and sales. Exchange runs via cron every 15–30 minutes.
Mobifitness — REST API with token authorization. Bitrix acts as the frontend, Mobifitness as the master system. HL FitnessSchedule is populated through synchronization.
The choice of architecture depends on the master system.
Client Personal Account
Built on the main module with extensions:
- Visit history — query from
FitnessBooking - Remaining visits —
UF_VISITS_LEFTfromUserSubscription - Membership renewal — button that creates an order
- Freeze/unfreeze
Authentication via phone with SMS code (module messageservice).
Trainer Profiles
Trainers are an infoblock with linkage to directions. On the detail page, we display the current week's class timetable (AJAX request to FitnessSchedule).
Implementation Timelines and Costs
| Project Scale | Composition | Timeline | Estimated Cost |
|---|---|---|---|
| Small club (1 hall, 5–7 directions) | Schedule, booking, memberships, personal account | 8–10 weeks | $15,000–$25,000 |
| Network of 3–5 clubs | Multi-site, unified database, integration with Mobifitness | 14–18 weeks | $40,000–$60,000 |
| Large network (10+ clubs) | B2B portal, mobile app via Bitrix REST, complex tiered pricing | 20–28 weeks | $80,000+ |
What's Included in the Work
- Free audit of current architecture and loads
- Design of high-load structures (HL blocks, indexes, triggers) — guaranteed 45x performance gain
- Development of schedule, online booking with waitlist, personal account
- Integration with 1С:Fitness Club or Mobifitness (certified developers)
- Configuration of tagged caching and composite mode
- Connection of payment gateways (YuKassa, Sber, ATOL) with 99.9% uptime SLA
- Administrator training and documentation handover
- 3 months of technical support after launch
Typical Mistakes in Schedule Design
- Using infoblocks for the class timetable — leads to slowdowns with 300+ classes.
- Missing
SELECT ... FOR UPDATElocks — duplicate bookings. - Storing the waitlist in the same infoblock — complicates logic and slows performance.
- Ignoring caching — server crashes under peak load.
- No master system — data conflicts between site and CRM.
Our team has 8+ years of certified experience with 1С-Bitrix, 15+ projects for fitness clubs, and a 5-year track record. High-load scheduling is our specialty. Before starting, define the master scheduling system and payment gateway — these affect architecture. Get a free consultation: contact us to discuss the details.







