diff --git a/lib/lb.c b/lib/lb.c
index a0426cc42e..a8b694d0b3 100644
--- a/lib/lb.c
+++ b/lib/lb.c
@@ -1082,7 +1082,10 @@ ovn_lb_datapaths_add_lr(struct ovn_lb_datapaths *lb_dps, size_t n,
                         struct ovn_datapath **ods)
 {
     for (size_t i = 0; i < n; i++) {
-        bitmap_set1(lb_dps->nb_lr_map, ods[i]->index);
+        if (!bitmap_is_set(lb_dps->nb_lr_map, ods[i]->index)) {
+            bitmap_set1(lb_dps->nb_lr_map, ods[i]->index);
+            lb_dps->n_nb_lr++;
+        }
     }
 }
 
@@ -1110,6 +1113,18 @@ ovn_lb_datapaths_remove_ls(struct ovn_lb_datapaths *lb_dps, size_t n,
     }
 }
 
+void
+ovn_lb_datapaths_remove_lr(struct ovn_lb_datapaths *lb_dps, size_t n,
+                           struct ovn_datapath **ods)
+{
+    for (size_t i = 0; i < n; i++) {
+        if (bitmap_is_set(lb_dps->nb_lr_map, ods[i]->index)) {
+            bitmap_set0(lb_dps->nb_lr_map, ods[i]->index);
+            lb_dps->n_nb_lr--;
+        }
+    }
+}
+
 struct ovn_lb_group_datapaths *
 ovn_lb_group_datapaths_create(const struct ovn_lb_group *lb_group,
                               size_t n_ls_datapaths,
@@ -1175,5 +1190,18 @@ void
 ovn_lb_group_datapaths_add_lr(struct ovn_lb_group_datapaths *lbg_dps,
                               struct ovn_datapath *lr)
 {
-    bitmap_set1(lbg_dps->nb_lr_map, lr->index);
+    if (!bitmap_is_set(lbg_dps->nb_lr_map, lr->index)) {
+        bitmap_set1(lbg_dps->nb_lr_map, lr->index);
+        lbg_dps->n_nb_lr++;
+    }
+}
+
+void
+ovn_lb_group_datapaths_remove_lr(struct ovn_lb_group_datapaths *lbg_dps,
+                                 struct ovn_datapath *lr)
+{
+    if (bitmap_is_set(lbg_dps->nb_lr_map, lr->index)) {
+        bitmap_set1(lbg_dps->nb_lr_map, lr->index);
+        lbg_dps->n_nb_lr--;
+    }
 }
diff --git a/lib/lb.h b/lib/lb.h
index 08723e8ef3..91eec0199b 100644
--- a/lib/lb.h
+++ b/lib/lb.h
@@ -185,6 +185,8 @@ void ovn_lb_datapaths_set_ls(struct ovn_lb_datapaths *, size_t n,
 
 void ovn_lb_datapaths_remove_ls(struct ovn_lb_datapaths *, size_t n,
                                 struct ovn_datapath **);
+void ovn_lb_datapaths_remove_lr(struct ovn_lb_datapaths *, size_t n,
+                                struct ovn_datapath **);
 
 struct ovn_lb_group_datapaths {
     struct hmap_node hmap_node;
@@ -214,6 +216,9 @@ void ovn_lb_group_datapaths_remove_ls(struct ovn_lb_group_datapaths *,
 
 void ovn_lb_group_datapaths_add_lr(struct ovn_lb_group_datapaths *,
                                    struct ovn_datapath *lr);
+void ovn_lb_group_datapaths_remove_lr(struct ovn_lb_group_datapaths *,
+                                      struct ovn_datapath *lr);
+
 struct ovn_controller_lb {
     struct hmap_node hmap_node;
 
diff --git a/northd/en-lflow.c b/northd/en-lflow.c
index db1bcbccd6..ea51f4e3e0 100644
--- a/northd/en-lflow.c
+++ b/northd/en-lflow.c
@@ -102,6 +102,11 @@ lflow_northd_handler(struct engine_node *node,
     if (!northd_data->change_tracked) {
         return false;
     }
+
+    if (northd_data->lrouters_changed) {
+        return false;
+    }
+
     const struct engine_context *eng_ctx = engine_get_context();
     struct lflow_data *lflow_data = data;
 
diff --git a/northd/en-northd.c b/northd/en-northd.c
index b3c03c54bd..a321eff323 100644
--- a/northd/en-northd.c
+++ b/northd/en-northd.c
@@ -188,6 +188,26 @@ northd_nb_logical_switch_handler(struct engine_node *node,
     return true;
 }
 
+bool
+northd_nb_logical_router_handler(struct engine_node *node,
+                                 void *data)
+{
+    struct northd_data *nd = data;
+    struct northd_input input_data;
+
+    northd_get_input_data(node, &input_data);
+
+    if (!northd_handle_lr_changes(&input_data, nd)) {
+        return false;
+    }
+
+    if (nd->change_tracked) {
+        engine_set_node_state(node, EN_UPDATED);
+    }
+
+    return true;
+}
+
 bool
 northd_sb_port_binding_handler(struct engine_node *node,
                                void *data)
diff --git a/northd/en-northd.h b/northd/en-northd.h
index 5674f4390c..739aa5e87f 100644
--- a/northd/en-northd.h
+++ b/northd/en-northd.h
@@ -16,6 +16,7 @@ void en_northd_cleanup(void *data);
 void en_northd_clear_tracked_data(void *data);
 bool northd_nb_nb_global_handler(struct engine_node *, void *data OVS_UNUSED);
 bool northd_nb_logical_switch_handler(struct engine_node *, void *data);
+bool northd_nb_logical_router_handler(struct engine_node *, void *data);
 bool northd_sb_port_binding_handler(struct engine_node *, void *data);
 bool northd_northd_lb_data_handler(struct engine_node *, void *data);
 
diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c
index 8f509ccdad..cdbd0a65c3 100644
--- a/northd/inc-proc-northd.c
+++ b/northd/inc-proc-northd.c
@@ -156,7 +156,6 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
 
     engine_add_input(&en_northd, &en_nb_port_group, NULL);
     engine_add_input(&en_northd, &en_nb_acl, NULL);
-    engine_add_input(&en_northd, &en_nb_logical_router, NULL);
     engine_add_input(&en_northd, &en_nb_mirror, NULL);
     engine_add_input(&en_northd, &en_nb_meter, NULL);
     engine_add_input(&en_northd, &en_nb_static_mac_binding, NULL);
@@ -185,6 +184,8 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
                      northd_nb_nb_global_handler);
     engine_add_input(&en_northd, &en_nb_logical_switch,
                      northd_nb_logical_switch_handler);
+    engine_add_input(&en_northd, &en_nb_logical_router,
+                     northd_nb_logical_router_handler);
 
     engine_add_input(&en_mac_binding_aging, &en_nb_nb_global, NULL);
     engine_add_input(&en_mac_binding_aging, &en_sb_mac_binding, NULL);
diff --git a/northd/northd.c b/northd/northd.c
index f8adcad763..52889bf92f 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -3977,6 +3977,90 @@ associate_ls_lb_groups(struct ovn_datapath *ls_od,
     }
 }
 
+static void
+associate_lr_lbs(struct ovn_datapath *lr_od, struct hmap *lb_datapaths_map)
+{
+    struct ovn_lb_datapaths *lb_dps;
+
+    free(lr_od->lb_uuids);
+    lr_od->lb_uuids = xcalloc(lr_od->nbr->n_load_balancer,
+                              sizeof *lr_od->lb_uuids);
+    lr_od->n_lb_uuids = lr_od->nbr->n_load_balancer;
+
+    if (!lr_od->lb_ips) {
+        lr_od->lb_ips = ovn_lb_ip_set_create();
+    }
+
+    for (size_t i = 0; i < lr_od->nbr->n_load_balancer; i++) {
+        const struct uuid *lb_uuid =
+            &lr_od->nbr->load_balancer[i]->header_.uuid;
+        lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, lb_uuid);
+        ovs_assert(lb_dps);
+        ovn_lb_datapaths_add_lr(lb_dps, 1, &lr_od);
+        build_lrouter_lb_ips(lr_od->lb_ips, lb_dps->lb);
+        lr_od->lb_uuids[i] = *lb_uuid;
+    }
+}
+
+static void
+associate_lr_lb_groups(struct ovn_datapath *lr_od,
+                       struct hmap *lb_group_datapaths_map,
+                       struct hmap *lb_datapaths_map)
+{
+    const struct nbrec_load_balancer_group *nbrec_lb_group;
+    struct ovn_lb_group_datapaths *lb_group_dps;
+
+    free(lr_od->lb_group_uuids);
+    lr_od->lb_group_uuids = xcalloc(lr_od->nbr->n_load_balancer_group,
+                                    sizeof *lr_od->lb_group_uuids);
+    lr_od->n_lb_group_uuids = lr_od->nbr->n_load_balancer_group;
+
+    /* Checking load balancer groups first, starting from the largest one,
+     * to more efficiently copy IP sets. */
+    size_t largest_group = 0;
+
+    for (size_t i = 1; i < lr_od->nbr->n_load_balancer_group; i++) {
+        if (lr_od->nbr->load_balancer_group[i]->n_load_balancer >
+            lr_od->nbr->load_balancer_group[largest_group]->n_load_balancer) {
+            largest_group = i;
+        }
+    }
+
+    for (size_t i = 0; i < lr_od->nbr->n_load_balancer_group; i++) {
+        size_t idx = (i + largest_group) % lr_od->nbr->n_load_balancer_group;
+
+        nbrec_lb_group = lr_od->nbr->load_balancer_group[idx];
+        const struct uuid *lb_group_uuid = &nbrec_lb_group->header_.uuid;
+
+        lb_group_dps =
+            ovn_lb_group_datapaths_find(lb_group_datapaths_map,
+                                        lb_group_uuid);
+        ovs_assert(lb_group_dps);
+        ovn_lb_group_datapaths_add_lr(lb_group_dps, lr_od);
+
+        if (!lr_od->lb_ips) {
+            lr_od->lb_ips =
+                ovn_lb_ip_set_clone(lb_group_dps->lb_group->lb_ips);
+        } else {
+            for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) {
+                build_lrouter_lb_ips(lr_od->lb_ips,
+                                     lb_group_dps->lb_group->lbs[j]);
+            }
+        }
+
+        lr_od->lb_group_uuids[i] = *lb_group_uuid;
+
+        struct ovn_lb_datapaths *lb_dps;
+        for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) {
+            const struct uuid *lb_uuid =
+                &lb_group_dps->lb_group->lbs[j]->nlb->header_.uuid;
+            lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, lb_uuid);
+            ovs_assert(lb_dps);
+            ovn_lb_datapaths_add_lr(lb_dps, 1, &lr_od);
+        }
+    }
+}
+
 static void
 build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups,
                    struct ovn_datapaths *ls_datapaths,
@@ -3984,7 +4068,6 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups,
                    struct hmap *lb_datapaths_map,
                    struct hmap *lb_group_datapaths_map)
 {
-    const struct nbrec_load_balancer_group *nbrec_lb_group;
     struct ovn_lb_group_datapaths *lb_group_dps;
     const struct ovn_lb_group *lb_group;
     struct ovn_lb_datapaths *lb_dps;
@@ -4018,53 +4101,8 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups,
 
     HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) {
         ovs_assert(od->nbr);
-
-        /* Checking load balancer groups first, starting from the largest one,
-         * to more efficiently copy IP sets. */
-        size_t largest_group = 0;
-
-        for (size_t i = 1; i < od->nbr->n_load_balancer_group; i++) {
-            if (od->nbr->load_balancer_group[i]->n_load_balancer >
-                od->nbr->load_balancer_group[largest_group]->n_load_balancer) {
-                largest_group = i;
-            }
-        }
-
-        for (size_t i = 0; i < od->nbr->n_load_balancer_group; i++) {
-            size_t idx = (i + largest_group) % od->nbr->n_load_balancer_group;
-
-            nbrec_lb_group = od->nbr->load_balancer_group[idx];
-            const struct uuid *lb_group_uuid = &nbrec_lb_group->header_.uuid;
-
-            lb_group_dps =
-                ovn_lb_group_datapaths_find(lb_group_datapaths_map,
-                                            lb_group_uuid);
-            ovs_assert(lb_group_dps);
-            ovn_lb_group_datapaths_add_lr(lb_group_dps, od);
-
-            if (!od->lb_ips) {
-                od->lb_ips =
-                    ovn_lb_ip_set_clone(lb_group_dps->lb_group->lb_ips);
-            } else {
-                for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) {
-                    build_lrouter_lb_ips(od->lb_ips,
-                                         lb_group_dps->lb_group->lbs[j]);
-                }
-            }
-        }
-
-        if (!od->lb_ips) {
-            od->lb_ips = ovn_lb_ip_set_create();
-        }
-
-        for (size_t i = 0; i < od->nbr->n_load_balancer; i++) {
-            const struct uuid *lb_uuid =
-                &od->nbr->load_balancer[i]->header_.uuid;
-            lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, lb_uuid);
-            ovs_assert(lb_dps);
-            ovn_lb_datapaths_add_lr(lb_dps, 1, &od);
-            build_lrouter_lb_ips(od->lb_ips, lb_dps->lb);
-        }
+        associate_lr_lb_groups(od, lb_group_datapaths_map, lb_datapaths_map);
+        associate_lr_lbs(od, lb_datapaths_map);
     }
 
     HMAP_FOR_EACH (lb_group_dps, hmap_node, lb_group_datapaths_map) {
@@ -4934,6 +4972,7 @@ destroy_northd_data_tracked_changes(struct northd_data *nd)
     }
 
     nd->change_tracked = false;
+    nd->lrouters_changed = false;
 }
 
 /* Check if a changed LSP can be handled incrementally within the I-P engine
@@ -5429,6 +5468,263 @@ fail:
     return false;
 }
 
+/* Returns true if the logical router has changes which are not
+ * incrementally handled.
+ * Presently supports i-p for the below changes:
+ *    - load balancers and load balancer groups.
+ */
+static bool
+check_unsupported_inc_proc_for_lr_changes(
+    const struct nbrec_logical_router *lr)
+{
+    /* Check if the columns are changed in this row. */
+    enum nbrec_logical_router_column_id col;
+    for (col = 0; col < NBREC_LOGICAL_ROUTER_N_COLUMNS; col++) {
+        if (nbrec_logical_router_is_updated(lr, col)) {
+            if (col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER ||
+                col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER_GROUP) {
+                continue;
+            }
+            return true;
+        }
+    }
+
+    /* Check if the referenced rows are changed.
+       XXX: Need a better OVSDB IDL interface for this check. */
+    for (size_t i = 0; i < lr->n_ports; i++) {
+        if (nbrec_logical_router_port_row_get_seqno(lr->ports[i],
+                                OVSDB_IDL_CHANGE_MODIFY) > 0) {
+            return true;
+        }
+    }
+    if (lr->copp && nbrec_copp_row_get_seqno(lr->copp,
+                                OVSDB_IDL_CHANGE_MODIFY) > 0) {
+        return true;
+    }
+    for (size_t i = 0; i < lr->n_nat; i++) {
+        if (nbrec_nat_row_get_seqno(lr->nat[i],
+                                OVSDB_IDL_CHANGE_MODIFY) > 0) {
+            return true;
+        }
+    }
+    for (size_t i = 0; i < lr->n_policies; i++) {
+        if (nbrec_logical_router_policy_row_get_seqno(lr->policies[i],
+                                OVSDB_IDL_CHANGE_MODIFY) > 0) {
+            return true;
+        }
+    }
+    for (size_t i = 0; i < lr->n_static_routes; i++) {
+        if (nbrec_logical_router_static_route_row_get_seqno(
+            lr->static_routes[i], OVSDB_IDL_CHANGE_MODIFY) > 0) {
+            return true;
+        }
+    }
+    return false;
+}
+
+static bool
+lr_check_and_handle_lb_and_lbgrp_changes(
+    const struct nbrec_logical_router *changed_lr,
+    struct hmap *lb_datapaths_map, struct hmap *lb_group_datapaths_map,
+    struct ovn_datapath *od, bool *updated)
+{
+    ovs_assert(od->nbr);
+    bool lbs_changed = true;
+    if (!nbrec_logical_router_is_updated(changed_lr,
+                        NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER) &&
+        !nbrec_logical_router_is_updated(changed_lr,
+                        NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER_GROUP)) {
+        lbs_changed = false;
+        for (size_t i = 0; i < changed_lr->n_load_balancer_group; i++) {
+            if (nbrec_load_balancer_group_row_get_seqno(
+                    changed_lr->load_balancer_group[i],
+                    OVSDB_IDL_CHANGE_MODIFY) > 0) {
+                lbs_changed = true;
+                break;
+            }
+        }
+
+        if (!lbs_changed) {
+            for (size_t i = 0; i < changed_lr->n_load_balancer; i++) {
+                if (nbrec_load_balancer_row_get_seqno(
+                        changed_lr->load_balancer[i],
+                        OVSDB_IDL_CHANGE_MODIFY) > 0) {
+                    lbs_changed = true;
+                    break;
+                }
+            }
+        }
+
+        if (!lbs_changed) {
+            return true;
+        }
+    }
+
+    /* We need to do 2 things to handle the router for load balancer or
+     * load balancer groups.
+     *
+     * 1. Disassociate the logical router datapath from the already associated
+     *    load balancers/load balancer groups.
+     * 2. Associate the logical router datapath with the updated
+     *    load balancers/groups.
+     * */
+    struct ovn_lb_datapaths *lb_dps;
+    size_t i, j;
+    for (i = 0; i < od->n_lb_uuids; i++) {
+        lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, &od->lb_uuids[i]);
+        if (lb_dps) {
+            if (lb_dps->lb->routable) {
+                /* Can't handler if the load balancer has routable flag set.
+                 * This requires updating the router ports's routable
+                 * addresses. */
+                return false;
+            }
+            ovn_lb_datapaths_remove_lr(lb_dps, 1, &od);
+        }
+    }
+
+    struct ovn_lb_group_datapaths *lbg_dps;
+    for (i = 0; i < od->n_lb_group_uuids; i++) {
+        lbg_dps = ovn_lb_group_datapaths_find(lb_group_datapaths_map,
+                                              &od->lb_group_uuids[i]);
+        if (lbg_dps) {
+            ovn_lb_group_datapaths_remove_lr(lbg_dps, od);
+
+            if (install_ls_lb_from_router && od->n_ls_peers) {
+                ovn_lb_group_datapaths_remove_ls(lbg_dps, od->n_ls_peers,
+                                                 od->ls_peers);
+            }
+        }
+
+        for (j = 0; j < lbg_dps->lb_group->n_lbs; j++) {
+            const struct uuid *lb_uuid =
+                &lbg_dps->lb_group->lbs[j]->nlb->header_.uuid;
+            lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, lb_uuid);
+            if (lb_dps) {
+                if (lb_dps->lb->routable) {
+                    /* Can't handler if the load balancer has routable flag
+                     * set.  This requires updating the router ports's
+                     * routable addresses. */
+                    return false;
+                }
+                ovn_lb_datapaths_remove_lr(lb_dps, 1, &od);
+
+                if (install_ls_lb_from_router && od->n_ls_peers) {
+                    ovn_lb_datapaths_remove_ls(lb_dps, od->n_ls_peers,
+                                               od->ls_peers);
+                }
+            }
+        }
+    }
+
+    ovn_lb_ip_set_destroy(od->lb_ips);
+    od->lb_ips = NULL;
+    associate_lr_lb_groups(od, lb_group_datapaths_map, lb_datapaths_map);
+    associate_lr_lbs(od, lb_datapaths_map);
+
+    /* Do the job of build_lrouter_lbs_reachable_ips and
+     * build_lswitch_lbs_from_lrouter for this lrouter datapath. */
+    for (i = 0; i < od->nbr->n_load_balancer; i++) {
+        lb_dps = ovn_lb_datapaths_find(lb_datapaths_map,
+                                &od->nbr->load_balancer[i]->header_.uuid);
+        ovs_assert(lb_dps);
+        if (lb_dps->lb->routable) {
+            /* Can't handler if the load balancer has routable flag set.
+             * This requires updating the router ports's routable addresses. */
+            return false;
+        }
+        build_lrouter_lb_reachable_ips(od, lb_dps->lb);
+
+        if (install_ls_lb_from_router && od->n_ls_peers) {
+            ovn_lb_datapaths_add_ls(lb_dps, od->n_ls_peers, od->ls_peers);
+        }
+    }
+
+    for (i = 0; i < od->nbr->n_load_balancer_group; i++) {
+        const struct nbrec_load_balancer_group *nbrec_lb_group =
+            od->nbr->load_balancer_group[i];
+        lbg_dps = ovn_lb_group_datapaths_find(lb_group_datapaths_map,
+                                              &nbrec_lb_group->header_.uuid);
+        ovs_assert(lbg_dps);
+        if (install_ls_lb_from_router && od->n_ls_peers) {
+            ovn_lb_group_datapaths_add_ls(lbg_dps, od->n_ls_peers,
+                                          od->ls_peers);
+        }
+
+        for (j = 0; j < lbg_dps->lb_group->n_lbs; j++) {
+            build_lrouter_lb_reachable_ips(od, lbg_dps->lb_group->lbs[j]);
+
+            if (install_ls_lb_from_router && od->n_ls_peers) {
+                const struct uuid *lb_uuid =
+                    &lbg_dps->lb_group->lbs[j]->nlb->header_.uuid;
+                lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, lb_uuid);
+                ovs_assert(lb_dps);
+                if (lb_dps->lb->routable) {
+                    /* Can't handler if the load balancer has routable flag
+                     * set.  This requires updating the router ports's
+                     * routable addresses. */
+                    return false;
+                }
+                ovn_lb_datapaths_add_ls(lb_dps, od->n_ls_peers, od->ls_peers);
+            }
+        }
+    }
+
+    *updated = true;
+    /* Re-evaluate 'od->has_lb_vip' */
+    init_lb_for_datapath(od);
+    return true;
+}
+
+
+/* Return true if changes are handled incrementally, false otherwise.
+ * When there are any changes, try to track what's exactly changed and set
+ * northd_data->change_tracked accordingly: change tracked - true, otherwise,
+ * false. */
+bool
+northd_handle_lr_changes(const struct northd_input *ni,
+                         struct northd_data *nd)
+{
+    const struct nbrec_logical_router *changed_lr;
+
+    bool updated = false;
+
+    NBREC_LOGICAL_ROUTER_TABLE_FOR_EACH_TRACKED (changed_lr,
+                                             ni->nbrec_logical_router_table) {
+        if (nbrec_logical_router_is_new(changed_lr) ||
+            nbrec_logical_router_is_deleted(changed_lr)) {
+            goto fail;
+        }
+
+        struct ovn_datapath *od = ovn_datapath_find(
+                                    &nd->lr_datapaths.datapaths,
+                                    &changed_lr->header_.uuid);
+
+        /* Presently only able to handle load balancer and
+         * load balancer group changes. */
+        if (check_unsupported_inc_proc_for_lr_changes(changed_lr)) {
+            goto fail;
+        }
+
+        if (!lr_check_and_handle_lb_and_lbgrp_changes(changed_lr,
+                                                &nd->lb_datapaths_map,
+                                                &nd->lb_group_datapaths_map,
+                                                od, &updated)) {
+            goto fail;
+        }
+    }
+
+    if (updated) {
+        nd->change_tracked = true;
+        nd->lrouters_changed = true;
+    }
+
+    return true;
+fail:
+    destroy_northd_data_tracked_changes(nd);
+    return false;
+}
+
 bool
 northd_handle_sb_port_binding_changes(
     const struct sbrec_port_binding_table *sbrec_port_binding_table,
diff --git a/northd/northd.h b/northd/northd.h
index a79cc470c3..765720849a 100644
--- a/northd/northd.h
+++ b/northd/northd.h
@@ -119,8 +119,11 @@ struct northd_data {
     struct chassis_features features;
     struct sset svc_monitor_lsps;
     struct hmap svc_monitor_map;
+
+    /* Tracked data. */
     bool change_tracked;
     struct tracked_ls_changes tracked_ls_changes;
+    bool lrouters_changed;
 };
 
 struct lflow_data {
@@ -342,6 +345,8 @@ void ovnsb_db_run(struct ovsdb_idl_txn *ovnnb_txn,
 bool northd_handle_ls_changes(struct ovsdb_idl_txn *,
                               const struct northd_input *,
                               struct northd_data *);
+bool northd_handle_lr_changes(const struct northd_input *,
+                              struct northd_data *);
 void destroy_northd_data_tracked_changes(struct northd_data *);
 void northd_destroy(struct northd_data *data);
 void northd_init(struct northd_data *data);
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index da9bc16fd9..6f6f67510e 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -9687,6 +9687,14 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
 check ovn-nbctl --wait=sb ls-lb-del sw0 lb1
 check_engine_stats norecompute recompute
 
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl lr-lb-add lr0 lb1
+check_engine_stats norecompute recompute
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl lr-lb-del lr0 lb1
+check_engine_stats norecompute recompute
+
 # Test load balancer group now
 check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
 lbg1_uuid=$(ovn-nbctl create load_balancer_group name=lbg1)
@@ -9723,11 +9731,11 @@ check_engine_stats norecompute recompute
 
 check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
 check ovn-nbctl add logical_router lr0 load_balancer_group $lbg1_uuid
-check_engine_stats recompute recompute
+check_engine_stats norecompute recompute
 
 check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
 check ovn-nbctl clear logical_router lr0 load_balancer_group
-check_engine_stats recompute recompute
+check_engine_stats norecompute recompute
 
 AT_CLEANUP
 ])
