{"id":443,"date":"2025-03-25T18:48:04","date_gmt":"2025-03-25T18:48:04","guid":{"rendered":"https:\/\/imcodinggenius.com\/?p=443"},"modified":"2025-03-25T18:48:04","modified_gmt":"2025-03-25T18:48:04","slug":"auto-reload-in-ktor","status":"publish","type":"post","link":"https:\/\/imcodinggenius.com\/?p=443","title":{"rendered":"Auto-reload in Ktor"},"content":{"rendered":"<p>Together, we will learn how to enable the Ktor<strong> development mode<\/strong> in several ways and how <strong>auto-reload<\/strong> can help with the <strong>Kotlin HTML DSL app<\/strong> example. <\/p>\n<h2 class=\"wp-block-heading\">Quick Ktor Setup<\/h2>\n<p>As the first step, let\u2019s quickly prepare a basic Ktor application responding with HTML.<\/p>\n<p>To do so, let\u2019s navigate to the <a href=\"https:\/\/start.ktor.io\/\" target=\"_blank\" rel=\"noopener\">https:\/\/start.ktor.io<\/a> page and configure the artifact first:<\/p>\n<p>The choice is up to you here. From my end, I will be using the latest Ktor version with the YAML config and without the version catalog. <\/p>\n<p>Then, let\u2019s add the Kotlin HTML DSL plugin necessary for our simple example:<\/p>\n<p>Lastly, let\u2019s download the zip package, extract it, and import it to our IDE. <\/p>\n<p>If you are working in IntelliJ IDEA, then please make sure that you use JDK 23, too. <\/p>\n<p>You can do that in two places: <\/p>\n<p>Settings -&gt; Build, Execution, Deployment -&gt; Build Tools -&gt; Gradle. Here, please set the Gradle JVM to 23<\/p>\n<p>Project Structure -&gt; Project Settings -&gt; Project. On this page, please set the SDK to 23 and Language level to \u201cSDK default\u201d<\/p>\n<p>After all, please sync the gradle project and wait for the process to finish.<\/p>\n<h2 class=\"wp-block-heading\">Expose Endpoint Returning HTML<\/h2>\n<p>With all of that done, let\u2019s delete the unwanted files that were generated automatically, like Routing.kt, or Templating.kt and expose the endpoint:<\/p>\n<p>fun Application.module() {<\/p>\n<p>    routing {<br \/>\n        get(&#171;\/&#187;) {<br \/>\n            call.respondHtml {<br \/>\n                body {<br \/>\n                    + &#171;Hello world!&#187;<br \/>\n                }<br \/>\n            }<br \/>\n        }<br \/>\n    }<\/p>\n<p>}<\/p>\n<p>As we can see, whenever we reach the root path (by default, the localhost:8080), we should see the \u201cHello world!\u201d text.<\/p>\n<h2 class=\"wp-block-heading\">The Problem<\/h2>\n<p>Now, let\u2019s change the text, for example, to contain only a \u201cHello!\u201d message. <\/p>\n<p>What happens if we refresh the page? <strong>Nothing!<\/strong> The page does not reflect our code change until we restart the server manually! <\/p>\n<p>And, especially when dealing with HTML, it may become a pretty tedious task.<\/p>\n<h2 class=\"wp-block-heading\">Solution- Ktor auto-reload<\/h2>\n<p>It won\u2019t be a big surprise if I say that the <strong>Ktor auto-reload<\/strong> feature may be a great solution here?  <\/p>\n<p>But what is that?<\/p>\n<p>Well, long story short, it its a feature that we can turn on by <strong>enabling the development mode<\/strong> in Ktor. And when enabled, it <strong>reloads application classes on code changes<\/strong>. <\/p>\n<p>To be more specific, according to the documentation, Ktor listens for the changes to the following files:<\/p>\n<p>\/build\/classes\/kotlin\/main\/META-INF<br \/>\n\/build\/classes\/kotlin\/main\/com\/your-package-namn<br \/>\n\/build\/classes\/kotlin\/main\/com<br \/>\n\/build\/classes\/kotlin\/main<br \/>\n\/build\/resources\/main<\/p>\n<p>And as we can see, by the <strong>code changes<\/strong>, we mean the <strong>generated outputs and artifacts.<\/strong> But the good news is that with gradle, we can easily automate the generation, too.<\/p>\n<p>Lastly, I just wanted to mention that application logs are also pretty clear about what we need to do in order to enable auto-reload: <\/p>\n<p>2025-03-25 06:40:49.929 [main] INFO  Application &#8212; Autoreload is disabled because the development mode is off.<br \/>\n2025-03-25 06:40:50.072 [main] INFO  Application &#8212; Application started in 0.374 seconds.<br \/>\n2025-03-25 06:40:50.363 [DefaultDispatcher-worker-2] INFO  Application &#8212; Responding at http:\/\/127.0.0.1:8080<\/p>\n<h2 class=\"wp-block-heading\">Enable development mode<\/h2>\n<p>With all of that said, let\u2019s get back to the practice part. <\/p>\n<p>As the first step, we must enable the development mode. And we can do that in a few ways, so let me walk you through them.<\/p>\n<h2 class=\"wp-block-heading\">Hardcoded Approach<\/h2>\n<p>When we navigate to the build.gradle.kts file, we should see the following: <\/p>\n<p>application {<br \/>\n    mainClass = &#171;io.ktor.server.netty.EngineMain&#187;<\/p>\n<p>    val isDevelopment: Boolean = project.ext.has(&#171;development&#187;)<br \/>\n    applicationDefaultJvmArgs = listOf(&#171;-Dio.ktor.development=$isDevelopment&#187;)<br \/>\n}<\/p>\n<p>So the easy and the dummy approach would be to simply hardcode the value- -Dio.ktor.development=true: <\/p>\n<p>application {<br \/>\n    mainClass = &#171;io.ktor.server.netty.EngineMain&#187;<br \/>\n    applicationDefaultJvmArgs = listOf(&#171;-Dio.ktor.development=true&#187;)<br \/>\n}<\/p>\n<p>Now, when we run the app with .\/gradlew run, we will see that the message disappeared, proving the development mode is enabled:<\/p>\n<p>2025-03-25 07:10:15.883 [main] INFO  Application &#8212; Application started in 0.41 seconds.<br \/>\n2025-03-25 07:10:16.142 [main] INFO  Application &#8212; Responding at http:\/\/127.0.0.1:8080<br \/>\n&lt;==========&#8212;&gt; 83% EXECUTING [1m 13s]<\/p>\n<p>But first, this approach does not work if you run the server in IntelliJ by using the green icon because, by default, it does not invoke any gradle command.<\/p>\n<p>Secondly, it is hardcoded, meaning we don\u2019t have too much control over it in various environments. <\/p>\n<h2 class=\"wp-block-heading\">Program Argument<\/h2>\n<p>Another option is to bring back what we already had in the build.gradle.kts: <\/p>\n<p>val isDevelopment: Boolean = project.ext.has(&#171;development&#187;)<br \/>\napplicationDefaultJvmArgs = listOf(&#171;-Dio.ktor.development=$isDevelopment&#187;)<\/p>\n<p>And from now on, the only thing we need is the -Pdevelopment flag for the gradlew run command:<\/p>\n<p>.\/gradlew run -Pdevelopment<\/p>\n<p>It\u2019s clearly better and gives us more flexibility. <\/p>\n<h2 class=\"wp-block-heading\">VM options<\/h2>\n<p>Another option that we have on the table is to directly use the VM option we saw above- -Dio.ktor.development=true. <\/p>\n<p>For that purpose, we can even completely get rid of the previous snippet from application in build.gradle.kts: <\/p>\n<p>application {<br \/>\n    mainClass = &#171;io.ktor.server.netty.EngineMain&#187;<br \/>\n}<\/p>\n<p>And now, whenever invoking the gradlew run command, we will simply put the whole arg: <\/p>\n<p>.\/gradlew &#171;-Dio.ktor.development=true&#187; run<\/p>\n<p><strong>Moreover<\/strong>, when working with IntelliJ, we can edit our configuration to pass the same option: <\/p>\n<p>So we can see that this option will work with <strong>both gradle, as well as the IntelliJ IDEA runs.<\/strong> <\/p>\n<h2 class=\"wp-block-heading\">Config File<\/h2>\n<p>Lastly, we can also set that in the application.yaml:<\/p>\n<p>ktor:<br \/>\n    development: true<br \/>\n    application:<br \/>\n        modules:<br \/>\n            &#8212; com.codersee.ApplicationKt.module<br \/>\n    deployment:<br \/>\n        port: 8080<\/p>\n<p>It works exactly the same, and with environment variables can give us a lot of flexibility, too. <\/p>\n<h2 class=\"wp-block-heading\">Automate Build<\/h2>\n<p>Alright, so at this point, our app is <strong>up and running<\/strong> with the <strong>development mode ON.<\/strong> <\/p>\n<p>However, when we make any code change, <strong>nothing still happens!<\/strong> <\/p>\n<p>Well, as I mentioned previously, the Ktor auto-reload feature looks for the output files. Meaning we must build the project to see the changes. <\/p>\n<p>And we can do that by either running the .\/gradlew build or by navigating to the Build tab in IntelliJ: <\/p>\n<p>And although this works and we can now see changes without the restart, it is still not too convenient. <\/p>\n<p>Well, the good news we can slightly adjust the gradlew build command and <strong>automate that:<\/strong><\/p>\n<p>.\/gradlew -t build -x test<\/p>\n<p>With the -t flag (or &#8212;continuous), we enable the <strong>continuous build mode.<\/strong> Gradle will watch for changes in the source files, and whenever a relevant change is detected, it will automatically rerun the build task. <\/p>\n<p>Additionally, we exclude the test task using the -x flag to speed up the process a little  <\/p>\n<p>If we would like to add that as a run configuration to IntelliJ, then it is really easy, too: <\/p>\n<p>And basically, that\u2019s all! At this point, we can add the necessary HTML changes <strong>without restarting the Ktor server.<\/strong> <\/p>\n<h2 class=\"wp-block-heading\">Narrowing Down Watched Files<\/h2>\n<p>As I mentioned above, Ktor listens for the file updates in the following directories: <\/p>\n<p>\/build\/classes\/kotlin\/main\/META-INF<br \/>\n\/build\/classes\/kotlin\/main\/com\/your-package-namn<br \/>\n\/build\/classes\/kotlin\/main\/com<br \/>\n\/build\/classes\/kotlin\/main<br \/>\n\/build\/resources\/main<\/p>\n<p>If we would like to narrow down the list of watched directories, then we can do that, for example, in the YAML config file:<\/p>\n<p>ktor:<br \/>\n    deployment:<br \/>\n        watch:<br \/>\n            &#8212; resources<\/p>\n<p>The only thing we must specify is the part of the watched patch that we want to keep. <\/p>\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n<p>And that\u2019s all for this quick tutorial on how to enable the <strong>auto-reload feature in Ktor.<\/strong><\/p>\n<p>If you found this content useful, then check out my <a href=\"https:\/\/codersee.com\/courses\/ktor-server-pro\/\">Ktor Server Pro course<\/a>\u2013 the most comprehensive Ktor course on the market. <\/p>\n<p>Thank you for being here, and see you around!  <\/p>\n<p>The post <a href=\"https:\/\/codersee.com\/ktor-auto-reload\/\">Auto-reload in Ktor<\/a> appeared first on <a href=\"https:\/\/codersee.com\/\">Codersee &#8212; Kotlin on the backend<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>Together, we will learn how to enable the Ktor development mode in several ways and how auto-reload can help with the Kotlin HTML DSL app example. Quick Ktor Setup As the first step, let\u2019s quickly prepare a basic Ktor application responding with HTML. To do so, let\u2019s navigate to the &#8230; <\/p>\n<div><a class=\"more-link bs-book_btn\" href=\"https:\/\/imcodinggenius.com\/?p=443\">Read More<\/a><\/div>\n","protected":false},"author":0,"featured_media":444,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-443","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-news"],"_links":{"self":[{"href":"https:\/\/imcodinggenius.com\/index.php?rest_route=\/wp\/v2\/posts\/443"}],"collection":[{"href":"https:\/\/imcodinggenius.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/imcodinggenius.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/imcodinggenius.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=443"}],"version-history":[{"count":0,"href":"https:\/\/imcodinggenius.com\/index.php?rest_route=\/wp\/v2\/posts\/443\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/imcodinggenius.com\/index.php?rest_route=\/wp\/v2\/media\/444"}],"wp:attachment":[{"href":"https:\/\/imcodinggenius.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=443"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/imcodinggenius.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=443"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/imcodinggenius.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=443"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}