Quickstart
Add Skipper to a JVM service and run your first workflow — with zero database setup.
This guide gets Skipper running in an existing JVM service in a few minutes. For a deeper, worked example with tests, see Your First Workflow.
Package coordinates and module names below are illustrative and will be finalized with the first public release.
1. Add the dependency
Add Skipper to your build.
// build.gradle.kts
dependencies {
implementation("dev.skipper:skipper:0.1.0")
}
If you write workflows in Kotlin, also enable the AllOpen compiler plugin so Skipper can subclass your workflow and action classes (see Kotlin Coroutines).
2. Configure Skipper
Skipper is configured through a SkipperConfig. The only required setting is a unique service
name. By default Skipper persists to an embedded, in-memory SQLite store — so there is
nothing else to set up to start experimenting: no database to provision and no schema to
create.
val config = SkipperConfig.forService("my-service")
SkipperConfig config = SkipperConfig.forService("my-service");
The in-memory store is ideal for getting started, local development, and tests — but it is not durable: its state is lost when the process exits. For production, point Skipper at a persistent backend such as MySQL. See Storage Backends.
3. Create the runtime and start the scheduler
SkipperRuntime wires up the engine from your config. Start its scheduler so workflows are
driven forward, and keep the runtime around to obtain the workflow factory.
val runtime = SkipperRuntime(config)
// Start the scheduler (stop it on shutdown).
runtime.skipperSchedulerManager.get().start()
// Optional: expose the admin UI by registering this JAX-RS resource with your HTTP layer.
// See Observability & Admin UI for details.
val admin = runtime.adminResource.get()
SkipperRuntime runtime = new SkipperRuntime(config);
// Start the scheduler (stop it on shutdown).
runtime.getSkipperSchedulerManager().get().start();
// Optional: expose the admin UI by registering this JAX-RS resource with your HTTP layer.
// See Observability & Admin UI for details.
AdminResource admin = runtime.getAdminResource().get();
4. Write a workflow
A workflow is a class with at least one @WorkflowMethod. An action is a method on an
Actions class, annotated with @Execute, where you perform I/O and side effects.
class GreetingWorkflow : Workflow() {
private val actions = actions<GreetingActions>()
@WorkflowMethod
suspend fun greet(name: String): String = actions.render(name)
}
class GreetingActions : Actions() {
@Execute
suspend fun render(name: String): String = "Hello, $name!"
}
public class GreetingWorkflow extends Workflow {
private final GreetingActions actions = actions(GreetingActions.class);
@WorkflowMethod(returnType = String.class)
public CompletableFuture<String> greet(String name) {
return CompletableFuture.completedFuture(actions.render(name));
}
}
public class GreetingActions extends Actions {
@Execute
public String render(String name) {
return "Hello, " + name + "!";
}
}
5. Invoke it
Get the workflow factory from the runtime and start an instance with a unique id.
val factory: IWorkflowFactory = runtime.workflowFactory.get()
val workflow = factory<GreetingWorkflow>("greeting-42")
val result = workflow.greet("world") // suspends until the workflow completes
IWorkflowFactory factory = runtime.getWorkflowFactory().get();
GreetingWorkflow workflow = factory.invoke(GreetingWorkflow.class, "greeting-42");
String result = workflow.greet("world").get(); // blocks until the workflow completes
That’s it — Skipper persists progress as the workflow runs and will drive it to completion even if the process restarts mid-flight.
Next steps
- Understand the model: Core Concepts.
- Build and test a real one: Your First Workflow.