Core Annotations
This section documents the core annotations used to define options and how the compiler interprets them. These annotations control how Ktorgen scans interfaces, generates client factories, and connects them to Ktor’s HTTP client.
🧩 @KtorGen
The main entry point annotation for Ktorgen. It’s applied to an interface or its companion object that defines the HTTP endpoints and client configuration.
Definition (source)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.SOURCE)
annotation class KtorGen(
val name: String = KTORGEN_DEFAULT_NAME,
val generate: Boolean = true,
@property:Language("http-url-reference")
val basePath: String = "",
val generateTopLevelFunction: Boolean = true,
val generateCompanionExtFunction: Boolean = false,
val generateHttpClientExtension: Boolean = false,
@property:KtorGenExperimental
val propagateAnnotations: Boolean = true,
@property:KtorGenExperimental
val annotations: Array<KClass<out Annotation>> = [],
@property:KtorGenExperimental
val optInAnnotations: Array<KClass<out Annotation>> = [],
@property:KtorGenExperimental
val functionAnnotations: Array<KClass<out Annotation>> = [],
@property:KtorGenExperimental
val visibilityModifier: String = KTORGEN_DEFAULT_NAME,
@property:KtorGenExperimental
val classVisibilityModifier: String = KTORGEN_DEFAULT_NAME,
@property:KtorGenExperimental
val constructorVisibilityModifier: String = KTORGEN_DEFAULT_NAME,
@property:KtorGenExperimental
val functionVisibilityModifier: String = KTORGEN_DEFAULT_NAME,
val customFileHeader: String = KTORGEN_DEFAULT_NAME,
val customClassHeader: String = "",
)
Description
Marks an interface as a Ktorgen API.
The compiler will analyze all annotated functions within this interface and generate an implementation that uses io.ktor.client.HttpClient under the hood.
| Parameter | Type | Description | Default value |
|---|---|---|---|
name |
String |
Optional identifier used to name the generated client class. | Interface name with _ prefix and Impl suffix. |
generate |
Boolean |
Whether the annotated interface participates in code generation. | true |
basePath |
String |
Base path or URL prepended to all relative endpoints in functions. | "" |
generateTopLevelFunction |
Boolean |
Generate a top-level factory function in the same package. | true |
generateCompanionExtFunction |
Boolean |
Generate a companion extension factory (.create(HttpClient)). Requires a companion object declared |
false |
generateHttpClientExtension |
Boolean |
Generate an extension on HttpClient to instantiate the client. (.createMyApi()) |
false |
propagateAnnotations |
Boolean (Experimental) |
Copy annotations from interface to generated code. | true |
annotations |
Array<KClass<out Annotation>> (Experimental) |
Explicit annotations to propagate. Only those with empty constructors or default values. | [] |
optInAnnotations |
Array<KClass<out Annotation>> (Experimental) |
@RequiresOptIn annotations to be added to generated code with OptIn(). |
[] |
functionAnnotations |
Array<KClass<out Annotation>> (Experimental) |
Annotations to add to generated extension functions. | [] |
visibilityModifier |
String (Experimental) |
Global visibility (public, internal). |
Same as interface |
classVisibilityModifier |
String (Experimental) |
Visibility for generated implementation class. | Same as visibilityModifier |
constructorVisibilityModifier |
String (Experimental) |
Visibility for generated primary constructor. | Same as visibilityModifier |
functionVisibilityModifier |
String (Experimental) |
Visibility for generated extension functions. | Same as visibilityModifier |
customFileHeader |
String |
Custom file-level comment inserted at top of generated file. | Generated notice |
customClassHeader |
String |
Custom KDoc comment or annotations for generated class. | "" |
Example
User code
@KtorGen(
name = "UserApiClient",
basePath = "/users/",
)
interface UserApi {
@GET("{id}")
suspend fun getUser(@Path("id") id: String): User
}
Generated code
@file:Suppress("...")
package ...
import ...
/** Generated by KtorGen */
@Generated
public class UserApiClient public constructor(
private val _httpClient: HttpClient,
) : UserApi {
/** Generated by KtorGen */
@Generated
override suspend fun getUser(id: String): User = _httpClient.request {
this.method = HttpMethod.Get
this.url {
this.takeFrom("""/users/${id.encodeURLPath()}""")
}
}.body()
}
@KtorGen(
basePath = "album/",
visibilityModifier = "internal",
classVisibilityModifier = "private",
functionAnnotations = [JvmSynthetic::class, InternalDeezerClient::class],
annotations = [InternalDeezerClient::class],
)
interface AlbumRoutes {
@GET("{id}")
@JvmSynthetic
suspend fun getById(@Path id: Long): Album
}
Generated code
@Generated
@InternalDeezerClient
@JvmSynthetic
internal fun AlbumRoutes(httpClient: HttpClient): AlbumRoutes = _AlbumRoutes(httpClient)
@Generated
@InternalDeezerClient
private class _AlbumRoutesImpl internal constructor(
private val _httpClient: HttpClient
) : AlbumRoutes {
@Generated
@JvmSynthetic
override suspend fun getById(id: Long): Album = _httpClient.request {
this.method = HttpMethod.Get
this.url {
this.takeFrom("album/$id")
}
}.body()
}
Notes
- Some parameters marked as experimental may generate invalid code depending on platform support or KSP version.
- Misconfigured visibility modifiers can lead
fatal error occurred, invalid visibilityor propagated annotations can lead tounresolved symbolsduring compilation. - Annotations like
@JvmOverloadsor@JvmSyntheticare only valid oncommon,jvm, orandroid; using them on multiplatform-specific configurations may fail, including annotation in params. - Custom annotations must have empty constructors to be propagated automatically when it's added as parameter.
- Works across all supported KMP targets.
- If you omit
name, the compiler generates a default class name based on the interface (_UserApiImpl). - You can inject a custom
HttpClientwhen instantiating the generated client. - Indentation can differ, but has 4 spaces by default*
- By default, the generated code have
@Generatedand comments indicate generated code.
⚙️ @KtorGenFunction
Marks a single function inside a @KtorGen interface as participating in code generation.
Allows fine-grained control over how annotations and visibility are transferred from the source definition to the generated method.
Definition (source)
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.SOURCE)
annotation class KtorGenFunction(
val generate: Boolean = true,
@property:KtorGenExperimental
val propagateAnnotations: Boolean = true,
@property:KtorGenExperimental
val annotations: Array<KClass<out Annotation>> = [],
@property:KtorGenExperimental
val optInAnnotations: Array<KClass<out Annotation>> = [],
val customHeader: String = "",
)
Description
When combined with standard HTTP annotations (@GET, @POST, etc.), this signals the compiler to generate a corresponding HTTP call implementation.
| Parameter | Type | Description | Default value |
|---|---|---|---|
generate |
Boolean |
Whether this function should generate code. | true |
propagateAnnotations |
Boolean (Experimental) |
Copy annotations from source method to generated method. | true |
annotations |
Array<KClass<out Annotation>> (Experimental) |
Explicit annotations to propagate as-is. Must have empty constructors or default values. | [] |
optInAnnotations |
Array<KClass<out Annotation>> (Experimental) |
Propagate @RequiresOptIn or @SubclassOptInRequired annotations. |
[] |
customHeader |
String |
Custom KDoc header for the generated implementation. | "" |
Example
User code
interface TodoApi {
@KtorGenFunction(generate = false)
suspend fun createTask(@Body task: Task): Response<Task> = "some default value..."
}
Generated code
@Generated
public class _TodoApiImpl public constructor(private val httpClient: HttpClient) : TodoApi
// Skip code generation of createTask because have a default value defined in the interface
User code
interface UserRoutes {
@GET("/users/{id}")
@KtorGenFunction(
propagateAnnotations = true,
annotations = [JvmSynthetic::class],
optInAnnotations = [ExperimentalApi::class],
customHeader = "Auto-generated API method"
)
@ExperimentalApi
suspend fun getUser(@Path id: Int): User
}
Generated code
/** Auto-generated API method */
@Generated
@OptIn(ExperimentalApi::class)
@JvmSynthetic
suspend fun getUser(id: Int): User = _httpClient.request {
this.method = HttpMethod.Get
this.url {
this.takeFrom("/users/$id")
}
}.body()
Notes
- Use
@KtorGenFunctionwhen a function requires explicit generation control, otherwise don't include it. - The processor will skip any function marked with
generate = false, except if it doesn't have default value because impl class must implement abstract members of the interface - Experimental properties (
propagateAnnotations,annotations,optInAnnotations) may cause invalid code if incompatible annotations are propagated. - In multiplatform projects, prefer keeping propagated annotations restricted to
common-compatible ones.
🧪 @KtorGenFunctionKmp (Experimental)
This is an experimental annotation designed for Kotlin Multiplatform (KMP). It allows you to define generated functions compatible across multiple platforms, particularly where expect/actual declarations are used.
Definition (source)
@KtorGenExperimental
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.SOURCE)
annotation class KtorGenFunctionKmp()
Description
When applied, the compiler can generate expect declarations for shared functions, which are then completed by platform-specific actual implementations.
Example
User code
@OptIn(KtorGenExperimental::class)
@KtorGenFunctionKmp
expect fun createAnalyticsApi(httpClient: HttpClient): AnalyticsApi
@KtorGen
interface AnalyticsApi {
@POST("/events")
suspend fun sendEvent(@Body event: Event)
}
Generated code (each platform)
actual fun createAnalyticsApi(httpClient: HttpClient): AnalyticsApi = _AnalyticsApiImpl(httpClient)
@Generated
public class _AnalyticsApiImpl public constructor(
private val _httpClient: HttpClient
) : AnalyticsApi {
@Generated
override suspend fun sendEvent(event: Event) {
this._httpClient.request {
this.method = HttpMethod.Post
this.url {
this.takeFrom("https://api.example.com/events")
}
this.setBody(event)
}
}
}
Notes
- Only recommended for advanced KMP setups.
- May produce unresolved symbols in some Kotlin versions if combined with JVM-specific annotations like
@JvmOverloads. - Intended to be stabilized once KSP adds full KMP common source generation support.
- Only
expect functionis supported with exact constructor properties. expect interfaceis not supported.
🪶 @Generated
This annotation is automatically inserted by the Ktorgen compiler into all generated source files.
Definition (source)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.FILE)
@Retention(AnnotationRetention.BINARY)
annotation class Generated
Description
Serves as a marker indicating that a file or class was generated automatically by the compiler. Used internally by Ktorgen and for developer awareness (e.g., IDE highlighting or lint exclusions).
Example
// in file level
@file:Generated
// in factory top-level function
@Generated
public fun WeatherApi(httpClient: HttpClient): WeatherApi = _WeatherApiImpl(httpClient)
// in class level
@Generated
public class _WeatherApiImpl public constructor(
private val _httpClient: HttpClient
) : WeatherApi {
// in member functions
@Generated
override suspend fun getForecast(city: String): Forecast = // ...
}
Notes
- Do not use this annotation manually.
- Future versions may include metadata such as the generator version, option to don't include it, custom annotation, etc.