context FEATURE allow explicit context compilation
diff --git a/src/context.c b/src/context.c
index 6aa42c1..e93db25 100644
--- a/src/context.c
+++ b/src/context.c
@@ -467,6 +467,44 @@
     return ly_ctx_new_yl_common(search_dir, data, format, options, lyd_parse_data_mem, ctx);
 }
 
+API LY_ERR
+ly_ctx_compile(struct ly_ctx *ctx)
+{
+    struct lys_module *mod;
+    uint32_t i;
+    ly_bool recompile = 0;
+
+    LY_CHECK_ARG_RET(NULL, ctx, LY_EINVAL);
+
+    for (i = 0; i < ctx->list.count; ++i) {
+        mod = ctx->list.objs[i];
+        if (mod->to_compile) {
+            /* if was not implemented, will be */
+            mod->implemented = 1;
+
+            recompile = 1;
+        }
+    }
+
+    if (!recompile) {
+        /* no recompilation needed */
+        return LY_SUCCESS;
+    }
+
+    /* recompile */
+    LY_CHECK_RET(lys_recompile(ctx, 0));
+
+    /* everything is fine, clear the flags */
+    for (i = 0; i < ctx->list.count; ++i) {
+        mod = ctx->list.objs[i];
+        if (mod->to_compile) {
+            mod->to_compile = 0;
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
 API uint16_t
 ly_ctx_get_options(const struct ly_ctx *ctx)
 {
@@ -477,15 +515,16 @@
 API LY_ERR
 ly_ctx_set_options(struct ly_ctx *ctx, uint16_t option)
 {
-    LY_ERR lyrc;
+    LY_ERR lyrc = LY_SUCCESS;
 
     LY_CHECK_ARG_RET(ctx, ctx, LY_EINVAL);
     LY_CHECK_ERR_RET(option & LY_CTX_NO_YANGLIBRARY, LOGARG(ctx, option), LY_EINVAL);
-    lyrc = LY_SUCCESS;
 
     if (!(ctx->flags & LY_CTX_SET_PRIV_PARSED) && (option & LY_CTX_SET_PRIV_PARSED)) {
         ctx->flags |= LY_CTX_SET_PRIV_PARSED;
-        if ((lyrc = lys_recompile(ctx, 0))) {
+        /* recompile to set the priv pointers */
+        lyrc = lys_recompile(ctx, 0);
+        if (lyrc) {
             ly_ctx_unset_options(ctx, LY_CTX_SET_PRIV_PARSED);
         }
     }
diff --git a/src/context.h b/src/context.h
index f540bd4..f208c95 100644
--- a/src/context.h
+++ b/src/context.h
@@ -188,6 +188,12 @@
                                         Setting this option by ::ly_ctx_set_options() may result in context recompilation.
                                         Resetting this option by ::ly_ctx_unset_options() cause that private
                                         objects will be set to NULL. */
+#define LY_CTX_EXPLICIT_COMPILE 0x80 /**< If this flag is set, the compiled modules and their schema nodes are
+                                        not automatically updated (compiled) on any context changes. In other words, they do
+                                        not immediately take effect. To do that, call ::ly_ctx_compile(). Changes
+                                        requiring compilation include adding new modules, changing their features,
+                                        and implementing parsed-only modules. This option allows efficient compiled
+                                        context creation without redundant recompilations. */
 
 /** @} contextoptions */
 
@@ -261,6 +267,15 @@
 LY_ERR ly_ctx_new_ylmem(const char *search_dir, const char *data, LYD_FORMAT format, int options, struct ly_ctx **ctx);
 
 /**
+ * @brief Compile (recompile) the context applying all the performed changes after the last context compilation.
+ * Should be used only if ::LY_CTX_EXPLICIT_COMPILE option is set, has no effect otherwise.
+ *
+ * @param[in] ctx Context to compile.
+ * @return LY_ERR return value.
+ */
+LY_ERR ly_ctx_compile(struct ly_ctx *ctx);
+
+/**
  * @brief Add the search path into libyang context
  *
  * To reset search paths set in the context, use ::ly_ctx_unset_searchdir() and then
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 97bbe2a..89c97ad 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -800,6 +800,12 @@
 
     assert(!mod->implemented);
 
+    if (mod->ctx->flags & LY_CTX_EXPLICIT_COMPILE) {
+        /* do not compile the module yet */
+        mod->to_compile = 1;
+        return LY_SUCCESS;
+    }
+
     /* we have module from the current context */
     m = ly_ctx_get_module_implemented(mod->ctx, mod->name);
     if (m) {
@@ -843,8 +849,14 @@
             return r;
         }
 
-        /* full recompilation */
-        return lys_recompile(mod->ctx, 1);
+        if (mod->ctx->flags & LY_CTX_EXPLICIT_COMPILE) {
+            /* just mark the module as changed */
+            mod->to_compile = 1;
+            return LY_SUCCESS;
+        } else {
+            /* full recompilation */
+            return lys_recompile(mod->ctx, 1);
+        }
     }
 
     /* implement this module and any other required modules, recursively */
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 564be73..1c4f79f 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -2316,6 +2316,8 @@
     struct lys_module **deviated_by; /**< List of modules that deviate this module ([sized array](@ref sizedarrays)) */
 
     ly_bool implemented;             /**< flag if the module is implemented, not just imported */
+    ly_bool to_compile;              /**< flag marking a module that was changed but not (re)compiled, see
+                                          ::LY_CTX_EXPLICIT_COMPILE. */
     uint8_t latest_revision;         /**< flag to mark the latest available revision:
                                           1 - the latest revision in searchdirs was not searched yet and this is the
                                           latest revision in the current context