Simon Korell, Niklas Weidmann
11. September 2026
Introduction
In our spring vacation, the two of us took a trip to Japan. Besides breathtaking nature and fascinating urban landscape, we were impressed by the easy-to-use ordering systems in many Japanese restaurants, even for foreigners like us. So for
this semester, we wanted to create such a system ourselves.
The system includes an application for restaurant guests, which can be used to order from table-mounted displays or from their private phones after scanning a QR code. The waiters and chefs also both get their separate panels, showing relevant information such as incoming orders and information about the session per table.
Goals
In our internship last semester, both of us already got to gain experience using AWS to host and manage an application.
Because of that, we wanted to use this lecture to use and experiment with alternatives to AWS to expand our horizon.
Furthermore, we wanted to gain more practical experience setting up GitLab CI/CD pipelines, compare using PaaS to IaaS and build a scalable application to keep up with potentially thousands of restaurants using the app.
Tech Stack
The following technologies we used for our project:
- Next.js and React+Vite as a framework for our different frontend applications
- Express 5 as a framework for our backend
- Socket.IO for real-time communication
- Supabase to host our PostgreSQL database
- Upstash for serverless Redis
- Vercel to host our frontend
- Railway to host our backend
- GitLab CI/CD for automated tests and deployment

The project is built as a monorepo containing the different directories for our backend and each of our frontend applications.
Architectural Decisions
Our architectural decisions were based on our goals and principles we agreed on at the beginning: finding and using (PaaS) alternatives to AWS, using GitLab CI/CD pipelines and keeping our applications scalable.
Supabase
Supabase is a well-known backend-as-a-service platform built on top of PostgreSQL, which we used for our persistent data storage. Using a relational database was the obvious solution for our well-structured restaurant data and both Postgres and Supabase are well established.
Supabase manages the database instance for us, allowing for easy setup and
management of our database. The database can also easily be scaled up if necessary and can nicely be integrated in our Node.js backend using the Supabase SDK.
Vercel
We decided to use Vercel for hosting our frontend application. Vercel is specialized for modern Next.js webapps, which was perfect for our use case. Being built on top of AWS, Vercel promises easier deployment and scaling, as well as a more user-friendly control plane, which was a good opportunity to experience the difference using IaaS (AWS) and PaaS (Vercel).
Furthermore, the free hobby plan was more than enough for our student project.
Railway
Since we need a persistent container running our backend compared to the serverless approach by Vercel, we looked for another platform to host our backend. Railway does exactly that, promising easy configuration and deployment
for permanently running backend applications.
Railway natively supports Docker, which we used to build our backend.
Similarly to Vercel, Railway also offers a free hobby plan with sufficient resources for our project. Railway, however, is not built on AWS and is more like a more DX-friendly competitor to AWS.
Upstash
We wanted to experiment with Redis to cache data and help with scalability of our app, without hosting and maintaining our own Redis server. Looking for alternatives, we found Upstash, a serverless approach for Redis.
This allowed us to use Redis in our application with Upstash handling provisioning, scaling and maintenance. We found Redis on Upstash to be easy to configure and the free plan was once again enough for our project.
GitLab CI/CD
One of our goals with this project was to gain a better understanding of CI/CD and to apply its principles in a practical setting. For this purpose, we used a GitLab CI/CD pipeline consisting of test, build and deployment stages.
Automated tests are run before the application is built and then deployed. This ensures that errors can be detected early and faulty changes cannot be deployed to the production environment.
The pipeline configuration is stored in the repository, making the CI/CD process version-controlled and transparent, with sensitive information being stored as protected GitLab CI/CD variables.
The test and build jobs are executed automatically on every push, whilst deployment jobs are tied to pushes on the main branch, so only changes intended for production are deployed.
Scalability
One of our main goals was to design our application with scalability in mind. We wanted our system to continue working quickly and efficiently even when a large number of guests attempt to use the app simultaneously.
To achieve this goal, we used the following approaches:
Avoiding tightly coupling our frontend and backend, which allows us to keep both parts interchangeable and to deploy and scale them separately based on demand.
Hosting them on separate platforms (Vercel and Railway) makes this even easier.
As described above, both Vercel and Railway deliver built-in, easy-to-use solutions for scalability. Vercel automatically deploys the application with a global Content Delivery Network to speed up loading times and reduce server load by caching
content on globally distributed servers. The CDN worked without complex configuration and we even got a few requests from outside of Germany.
Railway offers both vertical and horizontal scaling. The platform automatically serves resources based on demand (vertical scaling) and allowed us to deploy multiple replicas of our API services if needed (horizontal scaling).
On top of that, we also used Redis to cache data, leading to reduced loading times and load on the database.
Encountered Challenges
Deployment integration
One of the challenges we encountered during the development of our project was to get the cloud deployment up and running.
Initially, we intended to use the deployment integration provided by both Vercel and Railway by simply pasting the repository URL. We were eager to find out if deploying our application really was as easy as both platforms promised it was. However, this approach does not work with self-managed GitLab repositories like ours.
After discussing possible alternatives such as switching to different cloud providers, we decided to integrate the deployment process directly into our GitLab CI/CD pipeline. This way, Vercel and Railway do not need to have access to our repository.
Setting up the deployment jobs for our pipelines required us to deal with aspects such as deployment tokens, environment and project configuration, deploying different projects from our single monorepo and the different deployment procedures of the two platforms.
Through this process, we gained a better understanding of how CI/CD pipelines interact with external cloud services. What initially appeared to be a limitation of our infrastructure therefore turned into a valuable learning experience. Instead of relying entirely on the deployment mechanisms provided by the hosting platforms, we gained a better understanding of how testing, building, and deployment can be
orchestrated as a single automated process.
HTTP redirect
After getting the deployment on Vercel and Railway to work via GitLab CI/CD, we started to configure our projects on both platforms. This involved setting necessary environment variables. Setting sensitive information like tokens as protected
environment variables made sure that no security-relevant data got pushed to the repository whilst allowing us to manage them in a central location.
One of those variables for the frontend projects was the URL for our API hosted on Railway, which we copied directly from Railway. This URL, however, was a link to http:// instead of https://, which caused problems using the API, which
took us a while to find the reason for.
When making POST requests to our API using the http:// address, we found that
Railway redirected them to the https:// address via the 301 Moved Permanently HTTP code. In many cases, redirecting causes the request method to be set to GET as default, which also was the case here. Since the endpoint was not available via GET, we got a quite confusing 404 NOT FOUND error until we found the misconfigured variable.
Local vs cloud deployment
When developing this project, we first built the application to run locally until it was almost fully developed.
This approach worked well enough for building and developing the application, but caused us some problems when trying to deploy to the different cloud services later.
Even though we tried keeping the deployment to Vercel and Railway in mind
when developing the app, a few things just did not work when deploying to the cloud for the first time.
Common errors, for example, were hardcoded localhost addresses or relative paths, which could no longer be found in a cloud environment.
A better approach might have been to start with a working deployment pipeline and develop from there, so that errors like the above could have been found earlier or avoided completely.
Experience using Vercel and Railway
One of our main goals with this project was to explore alternatives to the established cloud provider AWS. We ended up using Vercel for our frontend applications and Railway for the backend.
Overall, our experience with both platforms was very positive, even though we did not get to try deploying our project by simply pasting the repository link.
Compared to AWS, we found the setup more straightforward and configuration effort to be smaller. Both platforms allowed us to deploy our projects with relatively few steps using the GitLab CI/CD, automatically detecting and building
the corresponding application.
At the same time, we found that this simplicity comes with certain limitations. While Vercel and Railway both offer a more DX-friendly platform, AWS offers significantly more services and allows for much more detailed control over infrastructure, networking, security and scaling.
For much larger applications, however, there is definitely room for discussion about using AWS or other IaaS providers, as their flexibility and better control offer big advantages. Moreover, we could also consider Kubernetes if managing many containers and services became necessary.
For our student project, however, the advantages of simpler deployment and reduced management effort outweighed these limitations.
Final thoughts
The journey from our initial idea to the final product was a challenging process, with several unexpected problems, changes, and new requirements along the way. However, working through these challenges was ultimately a valuable part
of the project.
Every problem we encountered, every discussion and technical decision we made, and every adjustment to our original plans helped us gain a better understanding of the practical challenges involved in developing and deploying a cloud-based application.
This project gave us the opportunity to experiment with many new technologies and alternatives to established cloud providers, such as Vercel, Railway and Upstash. We also gained more experience correctly using CI/CD in GitLab.
Initially, we did consider just using AWS for this project; however, we feel like finding and using other options than the one we already knew taught us more and, frankly, was more fun. We think both of us learned something new and hopefully, so did you reading this blog post.
Authors:
- Simon Korell
- Niklas Weidmann

Leave a Reply
You must be logged in to post a comment.