Understanding the Pipeline as Code concept with a Jenkinsfile stored in the repository, comparing Declarative and Scripted syntax, then writing and running the first Hello World pipeline via SCM checkout.

In episode 1 we closed with the conclusion: code is better than clicks. Episode 2 is the time to prove that sentence. We will write your first Jenkins Pipeline in the form of a Jenkinsfile file — and this is where you feel the philosophical difference from the Freestyle Project discussed earlier. The entire build flow, from checkout to notifications, will live inside the Git repository as code that can be reviewed, tested, and versioned.
This concept is called Pipeline as Code, and it is the foundation of almost everything you will build in this series. In this episode we will discuss the concept, compare the two syntaxes — Declarative and Scripted — then dissect the anatomy of a Declarative block and write a Hello World pipeline that runs directly from the repository via SCM checkout.
The core idea is simple: the pipeline definition is no longer configuration stored in the Jenkins database, but a file named Jenkinsfile placed at the root directory of your repository, alongside the application code.
Why is this a big change? Because the pipeline becomes part of the codebase:
With a single repository, you can even use the same Jenkinsfile to test on a testing Jenkins and run on a production Jenkins — the configuration can never be "forgotten to sync".
Jenkins provides two syntaxes for writing pipelines:
Declarative Pipeline is the modern syntax introduced in 2017. It is structured, based on predefined blocks, and very easy to read. Its structure always starts with the pipeline keyword and uses blocks such as stages and steps.
Scripted Pipeline is the original syntax based on pure Groovy. It is imperative — written like a regular program with node { ... }, stage called as a method, and full freedom to write loops, exception handling, and any programmatic logic.
| Aspect | Declarative | Scripted |
|---|---|---|
| Structure | Declarative blocks (pipeline, stages, steps) | Imperative, pure Groovy |
| Readability | High | Varies |
| Structural validation | Strict, earlier errors | Loose |
| Flexibility | Sufficient with script { } | Unlimited |
| Recommended? | Yes, modern standard | Only when complex logic is needed |
Tip
The golden rule: default to Declarative, and insert script { } only when you truly need pure Groovy logic inside it. Scripted remains important to understand — especially when reading old Jenkinsfiles or writing Shared Libraries in episode 9 — but it is rarely the choice for new pipelines.
A Declarative pipeline is composed of blocks that always start with the pipeline keyword. The basic framework consists of four required blocks:
| Block | Purpose |
|---|---|
pipeline | The wrapper around the entire pipeline definition |
agent | Determines where the pipeline executes (node, label, container) |
stages | The container holding one or more stage |
stage | A single logical phase of the pipeline (Build, Test, Deploy) |
steps | The concrete commands executed inside the stage |
The basic structure is like nested boxes: inside pipeline there is agent, then stages which contains a list of stage, and each stage contains steps. You can read it like an outline: "This pipeline runs anywhere, with the following phases, and in this phase we do this."
Let's write the simplest pipeline. Create a file named Jenkinsfile in your repository:
pipeline {
agent any
stages {
stage('Hello') {
steps {
echo 'Hello dari Jenkins Pipeline!'
}
}
}
}Let's break it down one by one:
agent any means the pipeline may run on any available executor. In episode 3 we will replace it with a specific label (agent with the docker-runner label) so work is directed to the right agent.stages defines the phases. Here there is only one stage('Hello').steps contains the execution steps — in this case the echo that prints a message to the build log.When this pipeline runs, Jenkins will display a single stage named Hello in the UI, and below it a log containing the message we printed. This may look trivial, but this is the framework that will later host hundreds of steps in your production pipeline.
The Jenkinsfile is not run by copying its contents into the UI — it is fetched directly from the repository. The correct way:
Jenkinsfile, then git push.hello-world, and select the Pipeline type.Git, fill in Repository URL with your repo URL, and leave Branch Specifier pointing at the main branch.Jenkinsfile (the file name at the repository root).pipeline {
agent any
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Hello') {
steps {
echo 'Kode berhasil diambil dari repository'
}
}
}
}Note the checkout scm step — this is the explicit command to fetch the source code into the workspace. In a pipeline from SCM, Jenkins automatically checks out when the build starts, but mentioning it as an explicit stage makes the flow more transparent and makes it easy for you to add a checkout again in multi-branch configuration (episode 4).
Important
When choosing Pipeline script from SCM, Jenkins reads the Jenkinsfile from the repository — not from the Script field above it. The two options are mutually exclusive: use only one. The most common beginner mistake is filling in Script in the UI while the repository already has a Jenkinsfile, then wondering why repository changes have no effect.
After the build finishes, pay attention to a few things on the build page:
If any syntax is wrong, a Declarative pipeline will display a clear parsing error in the Console Output — one of the advantages of a structured syntax.
Jenkinsfile (without an extension) and it is at the repository root, or adjust Script Path.*/main or */master.agent any misunderstood. This means "run anywhere", not "run only on the controller" — Jenkins will still pick a matching executor.pipeline block (Declarative) cannot freely mix with node { } (Scripted) at the top level — choose one syntax as the framework.In episode 2 you have:
Jenkinsfile inside the repository, reviewable and versionable like regular code.pipeline, agent, stages, stage, and steps.The key takeaway to carry with you: a pipeline is code, and that code lives in the repository. In episode 3 we will expand this architecture — building a distributed architecture with separate agents, understanding why the controller should not run production builds, and configuring SSH agents, Docker agents, and even Kubernetes agents. See you in episode 3!