diff --git a/juno_scheduler/src/compile.rs b/juno_scheduler/src/compile.rs
index 9d020c64ccef3b9c0a79694876c5b0ace606f938..0db32bdaee493bf934367072030a91d979f89812 100644
--- a/juno_scheduler/src/compile.rs
+++ b/juno_scheduler/src/compile.rs
@@ -275,6 +275,35 @@ fn compile_stmt(
                 limit,
             }])
         }
+        parser::Stmt::IfThenElse {
+            span: _,
+            cond,
+            thn,
+            els,
+        } => {
+            let cond = compile_exp_as_expr(cond, lexer, macrostab, macros)?;
+
+            macros.open_scope();
+            let thn = ir::ScheduleStmt::Block {
+                body: compile_ops_as_block(*thn, lexer, macrostab, macros)?,
+            };
+            macros.close_scope();
+
+            macros.open_scope();
+            let els = match els {
+                Some(els) => ir::ScheduleStmt::Block {
+                    body: compile_ops_as_block(*els, lexer, macrostab, macros)?,
+                },
+                None => ir::ScheduleStmt::Block { body: vec![] },
+            };
+            macros.close_scope();
+
+            Ok(vec![ir::ScheduleStmt::IfThenElse {
+                cond,
+                thn: Box::new(thn),
+                els: Box::new(els),
+            }])
+        }
         parser::Stmt::MacroDecl { span: _, def } => {
             let parser::MacroDecl {
                 name,
diff --git a/juno_scheduler/src/ir.rs b/juno_scheduler/src/ir.rs
index ab1495b816c99452560d03c0addf77a5aec18974..98f8050f2d32494db7a90b10b8c724a4b1848af6 100644
--- a/juno_scheduler/src/ir.rs
+++ b/juno_scheduler/src/ir.rs
@@ -180,4 +180,9 @@ pub enum ScheduleStmt {
         device: Device,
         on: Selector,
     },
+    IfThenElse {
+        cond: ScheduleExp,
+        thn: Box<ScheduleStmt>,
+        els: Box<ScheduleStmt>,
+    },
 }
diff --git a/juno_scheduler/src/lang.l b/juno_scheduler/src/lang.l
index af154fce3d489b7b078607e52888d76d08f8e5fe..1f4f8723de4d950920d503a11c9145ad1d15d24a 100644
--- a/juno_scheduler/src/lang.l
+++ b/juno_scheduler/src/lang.l
@@ -20,12 +20,15 @@
 \.              "."
 
 apply           "apply"
+else            "else"
 fixpoint        "fixpoint"
+if              "if"
 let             "let"
 macro           "macro_keyword"
 on              "on"
 set             "set"
 target          "target"
+then            "then"
 
 true            "true"
 false           "false"
diff --git a/juno_scheduler/src/lang.y b/juno_scheduler/src/lang.y
index 451f035b8122ac1a694567327a44776c9326fff2..55c82b9dc368e7cade9500fb852c9d48320be7d2 100644
--- a/juno_scheduler/src/lang.y
+++ b/juno_scheduler/src/lang.y
@@ -27,6 +27,10 @@ Stmt -> Stmt
       { Stmt::ExprStmt { span: $span, exp: $1 } }
   | 'fixpoint' FixpointLimit '{' Schedule '}'
       { Stmt::Fixpoint { span: $span, limit: $2, body: Box::new($4) } }
+  | 'if' Expr '{' Schedule '}'
+      { Stmt::IfThenElse { span: $span, cond: $2, thn: Box::new($4), els: None } }
+  | 'if' Expr '{' Schedule '}' 'else' '{' Schedule '}'
+      { Stmt::IfThenElse { span: $span, cond: $2, thn: Box::new($4), els: Some(Box::new($8)) } }
   | MacroDecl
       { Stmt::MacroDecl { span: $span, def: $1 } }
   ;
@@ -163,6 +167,7 @@ pub enum Stmt {
   AssignStmt { span: Span, var: Span, rhs: Expr },
   ExprStmt   { span: Span, exp: Expr },
   Fixpoint   { span: Span, limit: FixpointLimit, body: Box<OperationList> },
+  IfThenElse { span: Span, cond: Expr, thn: Box<OperationList>, els: Option<Box<OperationList>> },
   MacroDecl  { span: Span, def: MacroDecl },
 }
 
diff --git a/juno_scheduler/src/pm.rs b/juno_scheduler/src/pm.rs
index 62bdaf739b69b52a0b540c6a602e1e5beb632786..db1dfc9a56bb638bcc7af067d76ef16927213a72 100644
--- a/juno_scheduler/src/pm.rs
+++ b/juno_scheduler/src/pm.rs
@@ -1199,6 +1199,23 @@ fn schedule_interpret(
             // were made
             Ok(i > 1)
         }
+        ScheduleStmt::IfThenElse { cond, thn, els } => {
+            let (cond, modified) = interp_expr(pm, cond, stringtab, env, functions)?;
+            let Value::Boolean { val: cond } = cond else {
+                return Err(SchedulerError::SemanticError(
+                    "Condition must be a boolean value".to_string(),
+                ));
+            };
+            let changed = schedule_interpret(
+                pm,
+                if cond { &*thn } else { &*els },
+                stringtab,
+                env,
+                functions,
+            )?;
+
+            Ok(modified || changed)
+        }
         ScheduleStmt::Block { body } => {
             let mut modified = false;
             env.open_scope();