CI/CD Practical Guide (Part 1): What is CI/CD? How to Build a Stable and Efficient Development Team with CI/CD? Tool Selection?
Using the App (iOS) Team as an example, this guide introduces CI/CD from scratch and the tangible value it brings after implementation.

Photo by Leif Christoph Gottwald
2026 Update — Pricing changes for GitHub Actions (including Self-hosted Runner)
GitHub 2025/12/14 Latest Announcement:
-
January 1, 2026: GitHub-hosted Runner is now cheaper, with price reductions up to 39%.
-
March 1, 2026: Using Self-hosted Runner requires additional service maintenance fees, $0.002 USD per minute (regardless of OS), which equals $1 for 500 minutes. It is still cost-effective so far. ️
-
Public repositories still retain the same free tier.
GitHub will also invest more resources to enhance GitHub Actions features:
-
Scale Set Client: Simplifies the Autoscaling of Self-hosted Runners.
-
multi-label: Support Restart, improving the Runner label experience.
-
Actions Runner Controller (ARC) Update: Improved Deployment, Observability, and Version Management.
-
Actions Data Stream: Provides near real-time workflow/runner event data streams for monitoring and analysis.
The official pricing calculator has also been updated :

-
GitHub Hosted Runner — macOS 3-core(M1): $0.062 USD/minute, 1,000 minutes equals $62 USD
-
Self-Hosted Runner — $0.002 USD/minute, 1,000 minutes equals $2 USD
Buy the latest model Mac Mini 10-core (M4) yourself for about $600 USD, place it in the office as a Self-hosted Runner, and it will pay off in about a year; it offers better and faster performance with almost unlimited usage ( maintenance cost is minimal ).
You can also use retired old M1 MacBook Pro as a Runner = 0 cost.
*The above does not include electricity and internet costs.
Introduction
After two experiences building App CI/CD in different development teams, I finally have time to organize the journey from “why to do it” to “how to do it.” While I can’t guarantee this is the most standard CI/CD workflow, it is definitely a valuable starting point to help your team begin implementation, improve product stability, and boost overall development efficiency.
Chapter
This series will start by explaining “What CI/CD is and the value it brings,” followed by a hands-on guide on “How to set up a CI/CD environment using GitHub Actions + self-hosted Runner” and “Implementing CI and CD in app development as an example.” Finally, it will introduce how to “Use Google Apps Script Web App combined with GitHub Actions to create an easy-to-use app packaging platform for cross-team collaboration.” We hope this series is helpful to you.
Final Outcome
No more words, here is the final result.


Demo Web App (Please refer to the tutorial below for first-time use)
CI/CD — Fully developed with GitHub Actions, easy to maintain and extend.
CI:
-
Trigger Unit Tests Automatically on PR Submission
-
Run corresponding tests based on the scope of changed files
-
Merge PR only after tests have passed
CD:
-
Google Apps Script Web App (CD Packaging Interface) allows engineers, QA, and PMs to package the app on computers or mobile devices through this website.
-
GitHub Actions Self-hosted Runner: Using your own machine for unlimited CI/CD usage
-
Integrate Firebase App Distribution API to directly obtain the download link for the packaged test version
Automation :
-
Automatically assign yourself when creating a PR
-
Automatically assign reviewers randomly when creating a PR
-
Mark PR size label
Demo Web App/Project
- Online Demo Please refer to the authorization image below for first-time use (Only For Demo App):

What is CI/CD?
Story — Development Process Without CI/CD
Before discussing what CI/CD actually is, let’s set aside the term “CI/CD” and first recall how a startup development team without any workflow in place would work. The general process can be roughly summarized in the diagram below:

-
The product has a bug. Developer T creates a branch fix/bug-c from the main branch to fix it. After the fix, the branch is merged back into the main branch.
-
Next, Developer Z branched off from the main branch to create feature/a for requirement A. Halfway through, they noticed something was wrong with the feature. After investigating, they found that the current functionality was broken and the tests were failing, so they informed Developer T to fix it.
-
After all development is complete, Developer Z uses his computer to build the version for QA testing, repeatedly fixing and building. Once everything is confirmed to be fine, the feature is merged back into the main branch.
-
As the Sprint quickly comes to an end, the release package needs to be delivered to users; Developer Z puts aside their current work to help package from the main branch for QA to perform regression testing, similarly repeatedly fixing issues and repackaging, and finally submitting the packaged app for review.
-
Released to users after Apple/Google review is completed.
Problem
In the above story, we can summarize two major issues.
Question 1: There is no unified inspection mechanism for current correct feature changes.
-
Code That Does Not Follow the Coding Style Can Still Be Merged
-
Even If the Build Fails, I Can Still Merge
-
Changes can be merged even if basic Unit Tests and important checks fail.
-
My environment works correctly, but others may not have the same results.
-
Affects other developers currently working on the project
Question 2: Spending a lot of manpower and time on packaging work.
-
Packaging requires engineers to manually package, interrupting their current development work.
-
Switching back and forth between packaging and development incurs a high cognitive switching cost.
-
Packaging wait time prevents other development work from proceeding.
-
Engineers’ time cost is money.
-
Manual operations may cause errors.
-
QA asks engineers to package (back-and-forth communication).
CI — Continuous Integration 持續整合
Corresponding to Question 1, “Continuous Integration” aims to ensure that all changes automatically undergo Build & Test in a unified environment, guaranteeing that all modifications pass every test case and meet team standards before entering the production environment — “continuously and automatically ensuring the correct code is integrated into production.”
You can also add Nightly Builds and more automated testing steps to ensure stability.
CD — Continuous Delivery / Deployment Continuous Delivery / Deployment
For Question 2, “Continuous Deployment” aims to ensure that after the code passes the CI stage without issues, the changes are automatically packaged and deployed through the complex process to internal testing (QA, Debug, Staging, Beta…) or external release (Production, Release…).
-
Continuous Deployment: Fully automated deployment directly to the Production environment
-
Continuous Delivery: Automatically deploy only to the Staging/Debug environment; manual verification is required before deploying to the Production environment.
In the context of App development, it leans more towards Continuous Delivery, where we want a manual check to confirm everything is flawless before the App is officially released, ensuring the release timing and functionality are accurate.
Story — Building a Stable and Efficient Development Team through CI/CD

Looking back at our story, after implementing CI/CD:
-
CI
All changes must pass automated tests before merging into the main branch. Additionally, a Nightly Build scheduled automated testing process is added to improve stability. -
CD
All packaging uses CD uniformly, allowing Developer T and Developer Z to fully focus on business development, reducing manual communication and operational errors.
Team Work Efficiency and Product Stability 🚀🚀🚀🚀🚀
The Value of CI/CD
Combining the core agile development principle of “small steps, fast iterations,” CI/CD provides the foundation for stability and work efficiency during frequent continuous feature iterations.
Automatically Standardize Verification of Iteration Results
- Ensure all changes meet the expected results, do not affect other functions, and do not impact other team members
Automate Tedious Deployment Processes
- Allow team members to focus on core business development and reduce manual operation errors
The Effectiveness of CI/CD
Looking back at the 2021 Pinkoi talk “2021 Pinkoi Tech Career Talk — Secrets of High-Efficiency Engineering Teams,” the content basically revolves around the same points: “automation, reducing dependencies between people, and focusing on core business.” Implementing CI/CD fully aligns with these three directions, so we can use the same approach to estimate its effectiveness.
Another point to highlight is the cost of context switching:

After working continuously for a period, we enter a “flow” state where our thoughts and productivity peak, allowing us to produce the most effective output. However, if interrupted, it takes time to return to this flow state—here, we use 30 minutes as an example.
In scenarios without CI/CD, it might be: Spending a lot of time only to find out something was broken and then going back to communicate and fix it (CI), QA/PM asking engineers to help package the test version of the app (CD).
CI/CD Effectiveness Estimation

Team size: 6 people / calculated per month
Here, we take a monthly basis as an example. Without a CI/CD process, there are 4 unexpected main branch breakages each month, resulting in about 720 minutes spent on fixing and communication. Adding the time for monthly packaging of test and release versions, plus errors caused by manual operations, the total reaches around 1,010 minutes. With an engineer’s monthly salary of 80,000, this results in approximately 13,000 in wasted costs each month.
This missed estimating Starting 2026–03–01, Self-hosted requires a maintenance fee of $0.002 USD per minute, meaning running 500 minutes costs $1 USD.
CI/CD Setup Cost
-
Labor Cost:
Based on the implementation described in this series, it is estimated that 1 person needs about 10 days = 4,800 minutes to complete the work. (~= NT$36,384) -
Equipment and Running Costs:
Using GitHub Actions self-hosted Runner only requires purchasing 1–2 Mac Minis upfront or directly using existing retired MacBook Pros as CI/CD Runners.
For example, for a team of 6, purchasing a brand new Mac Mini with 32G RAM M4 Mini (= NT$40,900)
The total cost is about NT$80,000, with benefits starting to be realized after around six months.
Disclaimer: This is just one way to calculate benefits and may not be the most accurate; it is meant to give everyone a concept to extend, allowing management to see the value of CI/CD and authorize the implementation of the entire workflow.
Choosing CI/CD Tools
Cloud Services Bitrise / XCode Cloud
-
Bitrise: One of the earliest cloud services focused on App CI/CD. My first experience with CI/CD was using Bitrise. It offers a user-friendly and intuitive step editor, allowing quick setup of App CI/CD pipelines.
Drawbacks: Initially, it was a $99 flat fee. When Apple M-series processors first launched, they switched to usage-based billing (a form of lock-in), and our team’s monthly cost reached at least $500. So we migrated to GitHub Actions.
However, recently checking their website, they now offer 1 App / 1 Concurrent / unlimited usage / $89 per month. -
XCode Cloud: 100 hours / 1 month / $50 USD. The advantage is high integration with XCode and App development; however, the downside is it does not support Android and customizing some steps can be difficult. Still, for small pure iOS apps, I would consider using it again.
Really worried about cloud services locking you in, so I prefer to keep control in-house and consider on-premise solutions.
On-premise Services Jenkins / GitHub Actions / Gitlab CI/CD
-
Gitlab CI/CD:
It was launched earlier and offers more complete features than GitHub Actions. However, since our project is hosted on GitHub, we do not consider using Gitlab CI/CD. Both have similar functions, and this series will use GitHub Actions as an example. -
GitHub Actions
GitHub launched its CI/CD service in 2018, directly integrated with GitHub projects. It has been continuously updated and improved over the years, offering many pre-built steps (Marketplace) ready to use. It supports self-hosted runners, allowing unlimited use of your own machines (effectively a hybrid cloud). -
Jenkins:
An open-source, free tool dedicated to CI/CD, old but powerful; Jenkins covers everything from application-level task design and permission management to low-level service dispatch and execution. It also has Plugins available for direct use and was an essential tool for early DevOps CI/CD.
Jenkins v.s. GitHub Actions
TL;DR
For App Teams without dedicated DevOps staff, having App developers build and maintain a Jenkins environment from scratch is too challenging, with few people skilled in it and potential network security issues. Choosing GitHub Actions allows App developers to focus solely on designing the CI/CD process. By briefly reviewing the official documentation on writing workflows and starting Runners, they can quickly set up a free, stable, and secure CI/CD service.

The following comparison is based solely on setting up App CI/CD and may not apply to all technical scenarios.
Setup and Maintenance Difficulty Jenkins >>> GitHub Actions

Here is a simple layered diagram to explain the difference between the two. As mentioned earlier, Jenkins covers all functions from top to bottom, making self-hosting much more complex. In contrast, GitHub Actions only requires writing YAML workflows on GitHub. The local machine just needs to register a GitHub self-hosted Runner (completed with 5 commands), and GitHub will automatically dispatch tasks to the local machine. GitHub is responsible for maintaining everything else, including GitHub Actions/Runner version upgrades and task dispatch issues, so we don’t need to handle them.
Another troublesome point is that Jenkins is a service independent of Git, so communication between them must be done via APIs (e.g., GitHub API/WebHook), making the setup more complex.
I previously surveyed about 30 iOS developers around me. Only a handful (2) understood Jenkins, while more than 10 were using GitHub Actions. After all, you can complete CI/CD tasks just by writing some YAML.
Learning Difficulty Jenkins »> GitHub Actions
Refer only to the official documentation to learn the available YAML commands for GitHub Actions and how to run your own Runner locally.
Stability: GitHub Actions > Jenkins
In this aspect, I think GitHub Actions slightly outperforms Jenkins.
Jenkins may crash due to system upgrades or installing conflicting plugins (but if it’s running fine and you don’t touch it, it usually has no issues).
GitHub Actions depends on GitHub Service Status (if GitHub goes down, it will also be affected), but outages are rare, with an average uptime of 99.9%. If issues do occur, you just wait for them to be fixed.
Security: GitHub Actions > Jenkins
Considering that GitHub Actions/Runner services are maintained and automatically updated by GitHub itself, this may be safer than Jenkins, which requires manual updates.
Additionally, communication between Jenkins and GitHub requires opening API/WebHook ports, which is relatively risky. GitHub and GitHub Actions integrate seamlessly, and the relationship between GitHub Actions and the self-hosted Runner is observer mode. The self-hosted Runner requests tasks from GitHub, so the Runner itself does not need to open external ports.
However, in a fully closed network environment, Jenkins is more secure than GitHub Actions.
Permission Control Jenkins »> GitHub Actions
This point needs special emphasis for comparison: Jenkins allows setting up separate account login permissions for control; GitHub Actions is directly tied to the GitHub repo, so only users with repo permissions can use it.
This is why the following article uses GAS Web App to create a cross-team operation platform.
Using Jenkins Extensively »> GitHub Actions
For teams with a full DevOps team, Jenkins is undoubtedly still the preferred choice. After all, in other domains (such as Web, backend, Java…), Jenkins has been running the longest, offers the most useful plugins, and can unify the CI/CD setup for all teams, making management easier. It also supports complex CI/CD scenarios like backend deployment followed by automatic frontend deployment.
GitHub Actions later also supported cross-Repo Actions/Runners.
Third-Party Plugin Richness Jenkins > GitHub Actions
In terms of quantity, GitHub Actions outnumbers Jenkins, but Jenkins offers deeper and more powerful CI/CD features. Many of GitHub Actions are simply automation functions.
Feature Depth Jenkins »> GitHub Actions
This aspect is incomparable. Jenkins has been around for nearly 20 years, while GitHub Actions still needs to add many features; for example: permission management, secret management (currently only plain text is supported, key files must be converted to plain text first), Cache/Artifact currently only supports Cloud, and so on.
Additionally, GitHub Self-hosted Runner also supports Docker or k8s.
Customized Deep Jenkins »> GitHub Actions
Jenkins is fully controlled by yourself, allowing greater customization of permissions that can affect the entire system. GitHub Actions can only customize different steps at the application level.
For example, since the built-in Artifacts in GitHub Actions do not support self-hosted runners, you can only use a shell script in the step to copy files to another directory, and cannot customize Artifacts implementation yourself.
App CI/CD scenarios do not require very advanced features.
Usability GitHub Actions »> Jenkins
In terms of interface, GitHub Actions is a newer tool and is easier to use than Jenkins. Regarding script configuration, Jenkins uses Pipeline Scripts stored on Jenkins, while GitHub Actions uses YAML files managed with the project’s Git, making it easier to set up than Jenkins.
Cost Risk Jenkins > GitHub Actions
Jenkins is fully open-source and free to use, giving you complete control. GitHub Actions is partially open-source, but task dispatching and execution run on GitHub’s closed SaaS service. Currently, GitHub Actions is completely free; you only pay when using GitHub Runners. Starting from 2026-03-01, using self-hosted Runners will also incur a maintenance fee of $0.002 USD per minute source. Public repositories have free usage quotas for these fees.
The Purpose of Google Apps Script Web App and Why It Was Chosen
Another tool option is Google Apps Script Web App. The reason for needing this is that GitHub Actions’ built-in form feature is too basic (the interface is too technical and static) and its execution permissions are tied to the GitHub Repo. This makes it very inconvenient if we want to provide access to other functional team members.
As follows:

CD packaging usually requires the operator to fill in some information, such as Release Notes.
Therefore, we need an “interface” tool for other team members or even our own engineers to use more conveniently.
Required Scenario:
Fill in the required information on this more user-friendly “interface,” connect to project management tools (e.g., Jira, Asana) to fetch Tasks, or directly get the PR list from GitHub. Then select from the dropdown menu and submit, triggering GitHub Actions to start the build via the GitHub API.
Slack
When we first implemented CI/CD, we chose to integrate the Slack API to achieve a similar effect:

https://slack.com/intl/zh-tw/blog/productivity/workflow-builder-tools-automation-examples
- Partners can directly fill out forms in Slack, trigger CD packaging, and receive Slack notifications.
The operation is smooth and unified within everyday office tools (SSOT), requiring no relearning; however, the underlying issue is that development and maintenance costs are very high. One reason is that Slack Outgoing-Webhook API demands a very fast response (within 3 seconds), which basically rules out using FAAS services for simple integration (e.g., Cloud Functions, GAS, Lambda…).
Previously, a team member interested in automation and backend developed a complete backend service using Kotlin+ktor, then set up a server on GCP for Slack integration.
Development and maintenance costs are extremely high, and handover is very difficult.
Google Apps Script — Web App
Previously shared “Using Google Apps Script Web App Form to Connect Github Action CI/CD Workflow”:


The advantages of using Google Apps Script — Web App are:
-
Website Web
-
Similar to Google Workspace enterprise account permission management, access can be restricted to only Google accounts within the organization.
-
Completely Free
-
Function as a Service without the need to set up or maintain servers
-
Easier to maintain and hand over
-
Can be operated on mobile devices
-
AI Can Help!
Whether it’s ChatGPT or other AI tools, they are very familiar with GAS and can directly help us create packaging forms and connect to the GitHub API. -
Can also integrate with Jira, Asana, Slack notification APIs
For the second promotion, I switched to using GAS Web App for the team, which also received great feedback. The only difference from Slack is that you need to bookmark one more URL. When packaging is needed, just open the URL and operate the packaging through the web form.
Complete App CI/CD Tool Workflow
Here is the complete workflow. The next article will gradually introduce how to use and integrate each tool.

Tool Roles:
-
GitHub Actions: CI/CD workflow script code
-
GitHub Actions — Self-hosted Runner: The actual environment where CI/CD runs, using a self-hosted runner. You only need to cover the machine purchase cost and can run tasks without usage limits.
-
Google Apps Script Web App: Since packaging is not always done by engineers, a platform is needed for cross-functional team members; GAS Web App can quickly create a web tool and share the URL for others to use.
-
Asana/Jira: Project management tools that can integrate with the GAS Web App, allowing QA/PM to directly select the tasks they want to package.
-
Slack: Responsible for receiving execution result notifications
Scenario:
-
End-User (QA/PM/PD/Developer): Submit the packaging form via GAS Web App (fetch the Branch corresponding to the Jira or Asana task) -> GAS calls GitHub API -> triggers CD packaging GitHub Actions <- GitHub self-hosted runner listens for the task and pulls it to the machine for execution -> upon completion, Slack notification is sent, and GAS Web App packaging status is updated.
-
End-User (Developer): Open a PR, push a new commit to the PR -> Trigger the CI test process <- GitHub self-hosted runner listens for the task and pulls it to the machine for execution -> After completion, comment the test results and update Checks.
Summary
This article mainly provides an introduction to what CI/CD is and its benefits. Starting from the next article, we will dive into the technical aspects, guiding you step-by-step to understand and implement GitHub Actions CI/CD until achieving the final results mentioned earlier.
Series Articles:
🍺 Buy me a beer on PayPal





Comments